zoukankan      html  css  js  c++  java
  • 查看tomcat启动文件都干点啥---Catalina.java

      在前一章查看tomcat启动文件都干点啥---Bootstrap.java中我们得出结论,在Bootstrap中通过反射调用Catalina类中的getServer,start,stop,stopServer等方法,下面看一下Catalina类中给外部提供的公共方法:

      

      Start:其中Catalina类的入口当然是start方法.start方法实现了启动一个新的server事例的功能,看一下start方法的内容:  

     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对象提供的方法,

      

      其中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等说清楚。

      如果有不正确的地方请指正。大家共同学习。

  • 相关阅读:
    ubuntu使用iso作为本地源
    ubuntu配置简单的DNS服务器
    core data
    Core Animation教程
    制作framework&静态库
    notes
    textkit
    coretext
    nsset
    iOS Development Sites
  • 原文地址:https://www.cnblogs.com/fantiantian/p/3651105.html
Copyright © 2011-2022 走看看