设为首页 收藏本站
查看: 2638|回复: 0

[经验分享] 查看tomcat启动文件都干点啥---Catalina.java

[复制链接]

尚未签到

发表于 2015-8-10 16:07:07 | 显示全部楼层 |阅读模式
  在前一章查看tomcat启动文件都干点啥---Bootstrap.java中我们得出结论,在Bootstrap中通过反射调用Catalina类中的getServer,start,stop,stopServer等方法,下面看一下Catalina类中给外部提供的公共方法:
DSC0000.png
  Start:其中Catalina类的入口当然是start方法.start方法实现了启动一个新的server事例的功能,看一下start方法的内容:  


DSC0001.gif DSC0002.gif


1 public void start() {
2
3         if (getServer() == null) {
4             load();
5         }
6
7         if (getServer() == null) {
8             log.fatal("Cannot start server. Server instance is not configured.");
9             return;
10         }
11
12         long t1 = System.nanoTime();
13
14         // Start the new server
15         try {
16             getServer().start();
17         } catch (LifecycleException e) {
18             log.fatal(sm.getString("catalina.serverStartFail"), e);
19             try {
20                 getServer().destroy();
21             } catch (LifecycleException e1) {
22                 log.debug("destroy() failed for failed Server ", e1);
23             }
24             return;
25         }
26
27         long t2 = System.nanoTime();
28         if(log.isInfoEnabled()) {
29             log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
30         }
31
32         // Register shutdown hook
33         if (useShutdownHook) {
34             if (shutdownHook == null) {
35                 shutdownHook = new CatalinaShutdownHook();
36             }
37             Runtime.getRuntime().addShutdownHook(shutdownHook);
38
39             // If JULI is being used, disable JULI's shutdown hook since
40             // shutdown hooks run in parallel and log messages may be lost
41             // if JULI's hook completes before the CatalinaShutdownHook()
42             LogManager logManager = LogManager.getLogManager();
43             if (logManager instanceof ClassLoaderLogManager) {
44                 ((ClassLoaderLogManager) logManager).setUseShutdownHook(
45                         false);
46             }
47         }
48
49         if (await) {
50             await();
51             stop();
52         }
53     }
View Code  在Catalina中有个很重要的对象就是Server,先说明一下,在tomcat中实现Server接口的StandardServer对象,其中定义了socketServer,在此只作此说明,不展开介绍,在下一章中会专门对StandardServer类以及Server接口进行说明。
  在start方法中首先需要判断是否初始化了实现server接口的类(以后都称作server类,不要误解Server为一个类),如果没有的话,那么调用load方法。
  load方法中调用了一下几个方法:
  initDirs:将Bootstrap中定义的catalina.home的值赋给CATALINA_BASE_PROP属性。以及对java.io.tmpdir属性的验证,下面是initDirs的代码实现:  





1 protected void initDirs() {
2
3         String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP);
4         if (catalinaHome == null) {
5             // Backwards compatibility patch for J2EE RI 1.3
6             String j2eeHome = System.getProperty("com.sun.enterprise.home");
7             if (j2eeHome != null) {
8                 catalinaHome=System.getProperty("com.sun.enterprise.home");
9             } else if (System.getProperty(Globals.CATALINA_BASE_PROP) != null) {
10                 catalinaHome = System.getProperty(Globals.CATALINA_BASE_PROP);
11             }
12         }
13         // last resort - for minimal/embedded cases.
14         if(catalinaHome==null) {
15             catalinaHome=System.getProperty("user.dir");
16         }
17         if (catalinaHome != null) {
18             File home = new File(catalinaHome);
19             if (!home.isAbsolute()) {
20                 try {
21                     catalinaHome = home.getCanonicalPath();
22                 } catch (IOException e) {
23                     catalinaHome = home.getAbsolutePath();
24                 }
25             }
26             System.setProperty(Globals.CATALINA_HOME_PROP, catalinaHome);
27         }
28
29         if (System.getProperty(Globals.CATALINA_BASE_PROP) == null) {
30             System.setProperty(Globals.CATALINA_BASE_PROP,
31                                catalinaHome);
32         } else {
33             String catalinaBase = System.getProperty(Globals.CATALINA_BASE_PROP);
34             File base = new File(catalinaBase);
35             if (!base.isAbsolute()) {
36                 try {
37                     catalinaBase = base.getCanonicalPath();
38                 } catch (IOException e) {
39                     catalinaBase = base.getAbsolutePath();
40                 }
41             }
42             System.setProperty(Globals.CATALINA_BASE_PROP, catalinaBase);
43         }
44
45         String temp = System.getProperty("java.io.tmpdir");
46         if (temp == null || (!(new File(temp)).exists())
47                 || (!(new File(temp)).isDirectory())) {
48             log.error(sm.getString("embedded.notmp", temp));
49         }
50
51     }
View Code  其中首先是兼容J2EE RI 1.3,获取com.sun.enterprise.home属性的值赋值给catalinaHome,如果不存在com.sun.enterprise.home这个属性,将Bootstrap中定义的catalina.home的值赋给CATALINA_BASE_PROP属性,如果以上都不成立,那么就是获取当前目录赋给CATALINA_BASE_PROP属性。其实当前目录也就是将Bootstrap中定义的catalina.home的值。只是在tomcat中进行了很繁琐的验证,当然这是有必要的。
  createStartDigester:用来生成server.xml的操作,下面是代码实现:  





  1  protected Digester createStartDigester() {
  2         long t1=System.currentTimeMillis();
  3         // Initialize the digester
  4         Digester digester = new Digester();
  5         digester.setValidating(false);
  6         digester.setRulesValidation(true);
  7         HashMap<Class<?>, List<String>> fakeAttributes =
  8             new HashMap<Class<?>, List<String>>();
  9         ArrayList<String> attrs = new ArrayList<String>();
10         attrs.add("className");
11         fakeAttributes.put(Object.class, attrs);
12         digester.setFakeAttributes(fakeAttributes);
13         digester.setUseContextClassLoader(true);
14
15         // Configure the actions we will be using
16         digester.addObjectCreate("Server",
17                                  "org.apache.catalina.core.StandardServer",
18                                  "className");
19         digester.addSetProperties("Server");
20         digester.addSetNext("Server",
21                             "setServer",
22                             "org.apache.catalina.Server");
23
24         digester.addObjectCreate("Server/GlobalNamingResources",
25                                  "org.apache.catalina.deploy.NamingResources");
26         digester.addSetProperties("Server/GlobalNamingResources");
27         digester.addSetNext("Server/GlobalNamingResources",
28                             "setGlobalNamingResources",
29                             "org.apache.catalina.deploy.NamingResources");
30
31         digester.addObjectCreate("Server/Listener",
32                                  null, // MUST be specified in the element
33                                  "className");
34         digester.addSetProperties("Server/Listener");
35         digester.addSetNext("Server/Listener",
36                             "addLifecycleListener",
37                             "org.apache.catalina.LifecycleListener");
38
39         digester.addObjectCreate("Server/Service",
40                                  "org.apache.catalina.core.StandardService",
41                                  "className");
42         digester.addSetProperties("Server/Service");
43         digester.addSetNext("Server/Service",
44                             "addService",
45                             "org.apache.catalina.Service");
46
47         digester.addObjectCreate("Server/Service/Listener",
48                                  null, // MUST be specified in the element
49                                  "className");
50         digester.addSetProperties("Server/Service/Listener");
51         digester.addSetNext("Server/Service/Listener",
52                             "addLifecycleListener",
53                             "org.apache.catalina.LifecycleListener");
54
55         //Executor
56         digester.addObjectCreate("Server/Service/Executor",
57                          "org.apache.catalina.core.StandardThreadExecutor",
58                          "className");
59         digester.addSetProperties("Server/Service/Executor");
60
61         digester.addSetNext("Server/Service/Executor",
62                             "addExecutor",
63                             "org.apache.catalina.Executor");
64
65
66         digester.addRule("Server/Service/Connector",
67                          new ConnectorCreateRule());
68         digester.addRule("Server/Service/Connector",
69                          new SetAllPropertiesRule(new String[]{"executor"}));
70         digester.addSetNext("Server/Service/Connector",
71                             "addConnector",
72                             "org.apache.catalina.connector.Connector");
73
74
75         digester.addObjectCreate("Server/Service/Connector/Listener",
76                                  null, // MUST be specified in the element
77                                  "className");
78         digester.addSetProperties("Server/Service/Connector/Listener");
79         digester.addSetNext("Server/Service/Connector/Listener",
80                             "addLifecycleListener",
81                             "org.apache.catalina.LifecycleListener");
82
83         // Add RuleSets for nested elements
84         digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
85         digester.addRuleSet(new EngineRuleSet("Server/Service/"));
86         digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
87         digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
88         addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
89         digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
90
91         // When the 'engine' is found, set the parentClassLoader.
92         digester.addRule("Server/Service/Engine",
93                          new SetParentClassLoaderRule(parentClassLoader));
94         addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
95
96         long t2=System.currentTimeMillis();
97         if (log.isDebugEnabled()) {
98             log.debug("Digester for server.xml created " + ( t2-t1 ));
99         }
100         return (digester);
101
102     }
View Code  在具体说明之前,我觉得有必要对Digester进行一下说明,以为可能有很多人和我一样,目前为止还还不是很清楚Digester为什么东西,其实他就是一个XML解析器,在这里就是构造一下tomcat启动时候的各种参数,各种初始化方法,初始化server,listener,connector,Executor等数据,我觉得这里有很多内容可以展开来说,所以我打算把他放到下一个章节专门对tomcat中Digester进行说明。在这里特别需要注意的就是如下这部分内容:  



1         digester.addObjectCreate("Server",
2                                  "org.apache.catalina.core.StandardServer",
3                                  "className");
4         digester.addSetProperties("Server");
5         digester.addSetNext("Server",
6                             "setServer",
7                             "org.apache.catalina.Server");
8
9         digester.addObjectCreate("Server/GlobalNamingResources",
10                                  "org.apache.catalina.deploy.NamingResources");
11         digester.addSetProperties("Server/GlobalNamingResources");
12         digester.addSetNext("Server/GlobalNamingResources",
13                             "setGlobalNamingResources",
14                             "org.apache.catalina.deploy.NamingResources");
15
16         digester.addObjectCreate("Server/Listener",
17                                  null, // MUST be specified in the element
18                                  "className");
19         digester.addSetProperties("Server/Listener");
20         digester.addSetNext("Server/Listener",
21                             "addLifecycleListener",
22                             "org.apache.catalina.LifecycleListener");
23
24         digester.addObjectCreate("Server/Service",
25                                  "org.apache.catalina.core.StandardService",
26                                  "className");
27         digester.addSetProperties("Server/Service");
28         digester.addSetNext("Server/Service",
29                             "addService",
30                             "org.apache.catalina.Service");
31
32         digester.addObjectCreate("Server/Service/Listener",
33                                  null, // MUST be specified in the element
34                                  "className");
35         digester.addSetProperties("Server/Service/Listener");
36         digester.addSetNext("Server/Service/Listener",
37                             "addLifecycleListener",
38                             "org.apache.catalina.LifecycleListener");
39
40         //Executor
41         digester.addObjectCreate("Server/Service/Executor",
42                          "org.apache.catalina.core.StandardThreadExecutor",
43                          "className");
44         digester.addSetProperties("Server/Service/Executor");
45
46         digester.addSetNext("Server/Service/Executor",
47                             "addExecutor",
48                             "org.apache.catalina.Executor");
  比如这里面的digester.addSetNext("Server","setServer","org.apache.catalina.Server")这句话,在Digester类中的实现如下:   



1     public void addSetNext(String pattern, String methodName,
2                            String paramType) {
3
4         addRule(pattern,
5                 new SetNextRule(methodName, paramType));
6
7     }
  实现的内容就是把org.apache.catalina.Server以及setServer以SetNextRule的类型保存起来。看一下SetNextRule对象提供的方法,
DSC0003.jpg
  其中end方法的实现如下:  





    public void end(String namespace, String name) throws Exception {
// Identify the objects to be used
Object child = digester.peek(0);
Object parent = digester.peek(1);
if (digester.log.isDebugEnabled()) {
if (parent == null) {
digester.log.debug("[SetNextRule]{" + digester.match +
"} Call [NULL PARENT]." +
methodName + "(" + child + ")");
} else {
digester.log.debug("[SetNextRule]{" + digester.match +
"} Call " + parent.getClass().getName() + "." +
methodName + "(" + child + ")");
}
}
if(methodName.equals("setServer")){
System.out.println("111111111111111111");
}
// Call the specified method
        IntrospectionUtils.callMethod1(parent, methodName,
child, paramType, digester.getClassLoader());
}
View Code  在这里通过反射实现的方法调用。大家可能困惑到底是在哪发出rule.end调用动作的呢?下面还是要看一下Digester类,igester继承了org.xml.sax.ext.DefaultHandler2类,其中有一个endElement方法,这个方法在读完XML中每个Element的时候执行,看一下endElement方法在Digester中的实现:  





@Override
public void endElement(String namespaceURI, String localName,
String qName) throws SAXException {
boolean debug = log.isDebugEnabled();
if (debug) {
if (saxLog.isDebugEnabled()) {
saxLog.debug("endElement(" + namespaceURI + "," + localName +
"," + qName + ")");
}
log.debug("  match='" + match + "'");
log.debug("  bodyText='" + bodyText + "'");
}
// Parse system properties
bodyText = updateBodyText(bodyText);
// the actual element name is either in localName or qName, depending
// on whether the parser is namespace aware
String name = localName;
if ((name == null) || (name.length() < 1)) {
name = qName;
}
// Fire "body" events for all relevant rules
List<Rule> rules = matches.pop();
if ((rules != null) && (rules.size() > 0)) {
String bodyText = this.bodyText.toString();
for (int i = 0; i < rules.size(); i++) {
try {
Rule rule = rules.get(i);
if (debug) {
log.debug("  Fire body() for " + rule);
}
rule.body(namespaceURI, name, bodyText);
} catch (Exception e) {
log.error("Body event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("Body event threw error", e);
throw e;
}
}
} else {
if (debug) {
log.debug("  No rules found matching '" + match + "'.");
}
if (rulesValidation) {
log.warn("  No rules found matching '" + match + "'.");
}
}
// Recover the body text from the surrounding element
bodyText = bodyTexts.pop();
if (debug) {
log.debug("  Popping body text '" + bodyText.toString() + "'");
}
// Fire "end" events for all relevant rules in reverse order
if (rules != null) {
for (int i = 0; i < rules.size(); i++) {
int j = (rules.size() - i) - 1;
try {
Rule rule = rules.get(j);
if (debug) {
log.debug("  Fire end() for " + rule);
}
if(name.equals("setServer")){
System.out.println("1222");
}
rule.end(namespaceURI, name);
} catch (Exception e) {
log.error("End event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("End event threw error", e);
throw e;
}
}
}
// Recover the previous match expression
int slash = match.lastIndexOf('/');
if (slash >= 0) {
match = match.substring(0, slash);
} else {
match = "";
}
}
View Code  主要功能就是找出对应的rule来逐一调用rule.end方法。根据在Catalina.java类中digester添加的rule,就执行到了StandardServer类中的addService方法,设置的server对象,这部分内容很重要。
  configFile:返回配置文件conf/server.xml文件。在获取配置文件conf/server.xml出错的时候,就尝试去获取server-embed.xml文件,如果都不存在,那么直接返回。记录日志。
  initStreams:这个方法很简单只是做了一个tomcat自定义的流的重定向,
  getServer().init:设置一下server的状态,然后初始化网络配置。
  OK,load方法就说完了,很长。
  然后在start方法中启动server。至于start方法,我们不再本文中说明,等在以后的章节会专门介绍Server。
  然后在在当期运行环境中注册一个ShutdownHook,该钩子的作于就是当程序结束时候,将Catalina程序shutdown。
  到此为止,start方法就算是说完了。其中主要内容就是如何构造一个server对象。在以后会展开说明Server对象。
  Stop:另外一个被外部调用的方法就是stop方法,看一下stop方法的代码实现:  





  public void stop() {
try {
// Remove the ShutdownHook first so that server.stop()
// doesn't get invoked twice
if (useShutdownHook) {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
// If JULI is being used, re-enable JULI's shutdown to ensure
// log messages are not lost
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
true);
}
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// This will fail on JDK 1.2. Ignoring, as Tomcat can run
// fine without the shutdown hook.
        }
// Shut down the server
try {
Server s = getServer();
LifecycleState state = s.getState();
if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
&& LifecycleState.DESTROYED.compareTo(state) >= 0) {
// Nothing to do. stop() was already called
} else {
s.stop();
s.destroy();
}
} catch (LifecycleException e) {
log.error("Catalina.stop", e);
}
}
View Code  首先要移除在start方法中注册的钩子,否则在程序结束以后再次触发钩子中定义的事件,肯定会出错。然后就获取server对象,检查状态,如果在运行那么停止,然后将资源释放。stop方法简单很多。
  stopServer:先检查Server对象是否存在,如果不存在就创建一个新的,然后关闭server以及Server中定义的socket。
  
  Catalina中的内容大概就这么多了,很不过瘾的地方就是内容很多,没有办法全部展开,尤其是实现Server接口的Server对象,构建server的方法,希望在下面的章节中把如何通过Digester构建server,以及与次有很重要关系的Tomca的结构比如server,services,connector,container等说清楚。
  如果有不正确的地方请指正。大家共同学习。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-97103-1-1.html 上篇帖子: 如何自定义Tomcat Realm实现我们的用户认证需求 下篇帖子: 查看tomcat启动文件都干点啥---Bootstrap.java
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表