查看tomcat启动文件都干点啥---Catalina.java
在前一章查看tomcat启动文件都干点啥---Bootstrap.java中我们得出结论,在Bootstrap中通过反射调用Catalina类中的getServer,start,stop,stopServer等方法,下面看一下Catalina类中给外部提供的公共方法:
  
Start:其中Catalina类的入口当然是start方法.start方法实现了启动一个新的server事例的功能,看一下start方法的内容:
 public void start() {
         if (getServer() == null) {
             load();
         }
         if (getServer() == null) {
             log.fatal("Cannot start server. Server instance is not configured.");
             return;
         }
         long t1 = System.nanoTime();
         // Start the new server
         try {
             getServer().start();
         } catch (LifecycleException e) {
             log.fatal(sm.getString("catalina.serverStartFail"), e);
             try {
                 getServer().destroy();
             } catch (LifecycleException e1) {
                 log.debug("destroy() failed for failed Server ", e1);
             }
             return;
         }
         long t2 = System.nanoTime();
         if(log.isInfoEnabled()) {
             log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
         }
         // Register shutdown hook
         if (useShutdownHook) {
             if (shutdownHook == null) {
                 shutdownHook = new CatalinaShutdownHook();
             }
             Runtime.getRuntime().addShutdownHook(shutdownHook);
             // If JULI is being used, disable JULI's shutdown hook since
             // shutdown hooks run in parallel and log messages may be lost
             // if JULI's hook completes before the CatalinaShutdownHook()
             LogManager logManager = LogManager.getLogManager();
             if (logManager instanceof ClassLoaderLogManager) {
                 ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                         false);
             }
         }
         if (await) {
             await();
             stop();
         }
     }
在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的代码实现:
 protected void initDirs() {
         String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP);
         if (catalinaHome == null) {
             // Backwards compatibility patch for J2EE RI 1.3
             String j2eeHome = System.getProperty("com.sun.enterprise.home");
             if (j2eeHome != null) {
                 catalinaHome=System.getProperty("com.sun.enterprise.home");
             } else if (System.getProperty(Globals.CATALINA_BASE_PROP) != null) {
                 catalinaHome = System.getProperty(Globals.CATALINA_BASE_PROP);
             }
         }
         // last resort - for minimal/embedded cases.
         if(catalinaHome==null) {
             catalinaHome=System.getProperty("user.dir");
         }
         if (catalinaHome != null) {
             File home = new File(catalinaHome);
             if (!home.isAbsolute()) {
                 try {
                     catalinaHome = home.getCanonicalPath();
                 } catch (IOException e) {
                     catalinaHome = home.getAbsolutePath();
                 }
             }
             System.setProperty(Globals.CATALINA_HOME_PROP, catalinaHome);
         }
         if (System.getProperty(Globals.CATALINA_BASE_PROP) == null) {
             System.setProperty(Globals.CATALINA_BASE_PROP,
                                catalinaHome);
         } else {
             String catalinaBase = System.getProperty(Globals.CATALINA_BASE_PROP);
             File base = new File(catalinaBase);
             if (!base.isAbsolute()) {
                 try {
                     catalinaBase = base.getCanonicalPath();
                 } catch (IOException e) {
                     catalinaBase = base.getAbsolutePath();
                 }
             }
             System.setProperty(Globals.CATALINA_BASE_PROP, catalinaBase);
         }
         String temp = System.getProperty("java.io.tmpdir");
         if (temp == null || (!(new File(temp)).exists())
                 || (!(new File(temp)).isDirectory())) {
             log.error(sm.getString("embedded.notmp", temp));
         }
     }
其中首先是兼容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的操作,下面是代码实现:
  protected Digester createStartDigester() {
         long t1=System.currentTimeMillis();
         // Initialize the digester
         Digester digester = new Digester();
         digester.setValidating(false);
         digester.setRulesValidation(true);
         HashMap<Class<?>, List<String>> fakeAttributes =
             new HashMap<Class<?>, List<String>>();
         ArrayList<String> attrs = new ArrayList<String>();
         attrs.add("className");
         fakeAttributes.put(Object.class, attrs);
         digester.setFakeAttributes(fakeAttributes);
         digester.setUseContextClassLoader(true);
         // Configure the actions we will be using
         digester.addObjectCreate("Server",
                                  "org.apache.catalina.core.StandardServer",
                                  "className");
         digester.addSetProperties("Server");
         digester.addSetNext("Server",
                             "setServer",
                             "org.apache.catalina.Server");
         digester.addObjectCreate("Server/GlobalNamingResources",
                                  "org.apache.catalina.deploy.NamingResources");
         digester.addSetProperties("Server/GlobalNamingResources");
         digester.addSetNext("Server/GlobalNamingResources",
                             "setGlobalNamingResources",
                             "org.apache.catalina.deploy.NamingResources");
         digester.addObjectCreate("Server/Listener",
                                  null, // MUST be specified in the element
                                  "className");
         digester.addSetProperties("Server/Listener");
         digester.addSetNext("Server/Listener",
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
         digester.addObjectCreate("Server/Service",
                                  "org.apache.catalina.core.StandardService",
                                  "className");
         digester.addSetProperties("Server/Service");
         digester.addSetNext("Server/Service",
                             "addService",
                             "org.apache.catalina.Service");
         digester.addObjectCreate("Server/Service/Listener",
                                  null, // MUST be specified in the element
                                  "className");
         digester.addSetProperties("Server/Service/Listener");
         digester.addSetNext("Server/Service/Listener",
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
         //Executor
         digester.addObjectCreate("Server/Service/Executor",
                          "org.apache.catalina.core.StandardThreadExecutor",
                          "className");
         digester.addSetProperties("Server/Service/Executor");
         digester.addSetNext("Server/Service/Executor",
                             "addExecutor",
                             "org.apache.catalina.Executor");
         digester.addRule("Server/Service/Connector",
                          new ConnectorCreateRule());
         digester.addRule("Server/Service/Connector",
                          new SetAllPropertiesRule(new String[]{"executor"}));
         digester.addSetNext("Server/Service/Connector",
                             "addConnector",
                             "org.apache.catalina.connector.Connector");
         digester.addObjectCreate("Server/Service/Connector/Listener",
                                  null, // MUST be specified in the element
                                  "className");
         digester.addSetProperties("Server/Service/Connector/Listener");
         digester.addSetNext("Server/Service/Connector/Listener",
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
         // Add RuleSets for nested elements
         digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
         digester.addRuleSet(new EngineRuleSet("Server/Service/"));
         digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
         digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
         addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
         digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
         // When the 'engine' is found, set the parentClassLoader.
         digester.addRule("Server/Service/Engine",
                          new SetParentClassLoaderRule(parentClassLoader));
         addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
         long t2=System.currentTimeMillis();
         if (log.isDebugEnabled()) {
             log.debug("Digester for server.xml created " + ( t2-t1 ));
         }
         return (digester);
     }
在具体说明之前,我觉得有必要对Digester进行一下说明,以为可能有很多人和我一样,目前为止还还不是很清楚Digester为什么东西,其实他就是一个XML解析器,在这里就是构造一下tomcat启动时候的各种参数,各种初始化方法,初始化server,listener,connector,Executor等数据,我觉得这里有很多内容可以展开来说,所以我打算把他放到下一个章节专门对tomcat中Digester进行说明。在这里特别需要注意的就是如下这部分内容:
         digester.addObjectCreate("Server",
                                  "org.apache.catalina.core.StandardServer",
                                  "className");
         digester.addSetProperties("Server");
         digester.addSetNext("Server",
                             "setServer",
                             "org.apache.catalina.Server");
         digester.addObjectCreate("Server/GlobalNamingResources",
                                  "org.apache.catalina.deploy.NamingResources");
         digester.addSetProperties("Server/GlobalNamingResources");
         digester.addSetNext("Server/GlobalNamingResources",
                             "setGlobalNamingResources",
                             "org.apache.catalina.deploy.NamingResources");
         digester.addObjectCreate("Server/Listener",
                                  null, // MUST be specified in the element
                                  "className");
         digester.addSetProperties("Server/Listener");
         digester.addSetNext("Server/Listener",
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
         digester.addObjectCreate("Server/Service",
                                  "org.apache.catalina.core.StandardService",
                                  "className");
         digester.addSetProperties("Server/Service");
         digester.addSetNext("Server/Service",
                             "addService",
                             "org.apache.catalina.Service");
         digester.addObjectCreate("Server/Service/Listener",
                                  null, // MUST be specified in the element
                                  "className");
         digester.addSetProperties("Server/Service/Listener");
         digester.addSetNext("Server/Service/Listener",
                             "addLifecycleListener",
                             "org.apache.catalina.LifecycleListener");
         //Executor
         digester.addObjectCreate("Server/Service/Executor",
                          "org.apache.catalina.core.StandardThreadExecutor",
                          "className");
         digester.addSetProperties("Server/Service/Executor");
         digester.addSetNext("Server/Service/Executor",
                             "addExecutor",
                             "org.apache.catalina.Executor");
比如这里面的digester.addSetNext("Server","setServer","org.apache.catalina.Server")这句话,在Digester类中的实现如下:
public void addSetNext(String pattern, String methodName,
String paramType) { addRule(pattern,
new SetNextRule(methodName, paramType)); }
实现的内容就是把org.apache.catalina.Server以及setServer以SetNextRule的类型保存起来。看一下SetNextRule对象提供的方法,
  
其中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());
    }
在这里通过反射实现的方法调用。大家可能困惑到底是在哪发出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 = "";
} }
主要功能就是找出对应的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);
        }
    }
首先要移除在start方法中注册的钩子,否则在程序结束以后再次触发钩子中定义的事件,肯定会出错。然后就获取server对象,检查状态,如果在运行那么停止,然后将资源释放。stop方法简单很多。
stopServer:先检查Server对象是否存在,如果不存在就创建一个新的,然后关闭server以及Server中定义的socket。
Catalina中的内容大概就这么多了,很不过瘾的地方就是内容很多,没有办法全部展开,尤其是实现Server接口的Server对象,构建server的方法,希望在下面的章节中把如何通过Digester构建server,以及与次有很重要关系的Tomca的结构比如server,services,connector,container等说清楚。
如果有不正确的地方请指正。大家共同学习。
查看tomcat启动文件都干点啥---Catalina.java的更多相关文章
- 查看tomcat启动文件都干点啥---Bootstrap.java
		
在上一章查看tomcat启动文件都干点啥---catalina.bat,说了在catalina.bat中都走了什么流程,最重要的是,我们得出了如下这段命令: _EXECJAVA=start " ...
 - 查看tomcat启动文件都干点啥---catalina.bat(转)
		
在上一次查看tomcat启动文件都干点啥一文中,我们总结出,startup.bat文件的作用就是找到catalina.bat文件,然后把参数传递给它,在startup.bat中,调用catalina. ...
 - 查看tomcat启动文件都干点啥---catalina.bat
		
在上一次查看tomcat启动文件都干点啥一文中,我们总结出,startup.bat文件的作用就是找到catalina.bat文件,然后把参数传递给它,在startup.bat中,调用catalina. ...
 - 查看tomcat启动文件都干点啥---server对象
		
在上一章查看tomcat启动文件都干点啥---Catalina.java中说道了构造Server,,这次尝试着说一下Tomcat中Server的内容,首先看一下org.apache.catalina. ...
 - 查看tomcat启动文件都干点啥
		
以下所写的都是基于Windows 操作系统,tomcat7.0版本.一直在使用tomcat但是老实说对于tomcat本身并没有一个系统的掌握,今天饶有兴致的随便看了看,做了一点笔记,写一点心得,我本人 ...
 - Linux下如何查看tomcat是否启动、查看tomcat启动日志
		
在Linux系统下,重启Tomcat使用命令的操作! 1.首先,进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 使用Tomcat关闭命令 ./shutdown.sh ...
 - Linux下如何查看tomcat是否启动、查看tomcat启动日志(转)
		
在Linux系统下,重启Tomcat使用命令的操作! 1.首先,进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 使用Tomcat关闭命令 ./shutdown.sh ...
 - Tomcat启动报错:org.apache.catalina.LifecycleException: Failed to start component...java.util.zip.ZipException: error in opening zip file
		
1.项目环境 IntelliJ IDEA2018.1.6 apache-tomcat-8.0.53 基于springboot开发的项目 maven3.5.3 2.出现问题 从svn同步下项目 启动to ...
 - Tomcat启动报错org.apache.catalina.core.StandardContext listenerStart
		
感谢原文作者:西北码农 原文链接:https://blog.csdn.net/bitree1/article/details/72236633 解决方法: 1.检查配置信息有无异常:如 web.xml ...
 
随机推荐
- Docker背后的内核知识(二)
			
cgroups资源限制 上一节中Docker背后的内核知识(一),我们了解了Docker背后使用的资源隔离技术namespace,通过系统调用构建了一个相对隔离的shell环境,也可以称之为简单的“容 ...
 - Cakephp在Controller中显示sql语句
			
Cakephp在Controller中查询语句一般是: $this->Model->find(); 那么这条语句对应的sql语句是什么呢? 可以通过下面方法显示: 1. $dbo = Co ...
 - SSH的基本操作
			
一. 登陆SSH远程控制服务器 我们以192.168.100.42服务器为例. SSH乱码: LANG="zh_CN.GB18030" export LANG=zh_CN.gb23 ...
 - mvc项目限制请求类型
			
MVC 5限制所有HTTP请求必须是POST方式 这篇文章讲述了如何限制请求类型.
 - Spring4.0实战 rest相关
			
package com.paic.pay.merchant.web; import com.paic.pay.merchant.entity.MerchantUser; import com.paic ...
 - AngularJs 特性 之 双向数据绑定
			
<!DOCTYPE html> <html lang="en" ng-app> <head> <meta charset="UT ...
 - 【Luogu】P4159迷路(矩阵优化)
			
题目链接 将每个点拆成时刻1~9,然后根据题目要求连边,比如i-j有一条权为x的边就从点i-x向点j-1连一条边,表示经过x次之后可以到达. 然后就矩阵快速幂乱搞就好了. #include<cs ...
 - BZOJ 4569 [Scoi2016]萌萌哒 ——ST表 并查集
			
好题. ST表又叫做稀疏表,这里利用了他的性质. 显然每一个条件可以分成n个条件,显然过不了. 然后发现有许多状态是重复的,首先考虑线段树,没什么卵用. 然后ST表,可以每一层表示对应的区间大小的两个 ...
 - Linux系统——机制策略(一)
			
机制策略(一) 形而上谓之道:形而下谓之器: ————易经 LinuxUnix设计理念提供的一种机制不是策略:1.如果说机制是一种框架,那么,策略就是填充框架的一个个具体实施.机制提供的就是一种开放而 ...
 - 转载:LeetCode:5Longest Palindromic Substring 最长回文子串
			
本文转自:http://www.cnblogs.com/TenosDoIt/p/3675788.html 题目链接 Given a string S, find the longest palindr ...