查看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等說清楚。

  如果有不正確的地方請指正。大家共同學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM