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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章