1. 程式人生 > >Tomcat8.5原始碼分析-StandardHost

Tomcat8.5原始碼分析-StandardHost

StandardHost被啟動過程

1.      protected void startInternal() throws LifecycleException {  
2.    
3.          fireLifecycleEvent(CONFIGURE_START_EVENT, null);  
4.          setState(LifecycleState.STARTING);  
5.    
6.          globalNamingResources.start();//JNDI  
7.    
8.          // Start our defined Services  
9. synchronized (servicesLock) { 10. for (int i = 0; i < services.length; i++) { 11. services[i].start(); 12. } 13. } 14. }
這段程式碼是StandardServer裡面的,可以看到,裡面啟動了services,然後直接轉到StandService,然後StandardService的

startInternal啟動了StandardEngine程式碼見下圖。

1.  protected void startInternal() throws LifecycleException {  
2.    
3.          if(log.isInfoEnabled())  
4.              log.info(sm.getString("standardService.start.name", this.name));  
5.          setState(LifecycleState.STARTING);  
6.    
7.          // Start our defined Container first  
8.          
if (engine != null) { 9. synchronized (engine) { 10. engine.start(); 11. } 12. }

然後再看StandardEngine的startInternal()方法

1.  protected synchronized void startInternal() throws LifecycleException {  
2.    
3.         // Log our server identification information  
4.         if(log.isInfoEnabled())  
5.             log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());  
6.    
7.         // Standard container startup  
8.         super.startInternal();  
9.     }  

可以看到這個地方有super.startInternal(); 這個super繼承了containerBase這個抽象基礎類,這個抽象基礎類是container介面的實現,我們可以看一下下面這段程式碼:

1.  protected synchronized void startInternal() throws LifecycleException {  
2.    
3.          // Start our subordinate components, if any  
4.          //開始下一級的元件,如果有的話  
5.          logger = null;  
6.          getLogger();  
7.          //如果配置了叢集元件,則啟動  
8.          Cluster cluster = getClusterInternal();  
9.          if (cluster instanceof Lifecycle) {  
10.             ((Lifecycle) cluster).start();  
11.         }  
12.         //如果配置了安全元件,則啟動  
13.         Realm realm = getRealmInternal();  
14.         if (realm instanceof Lifecycle) {  
15.             ((Lifecycle) realm).start();  
16.         }  
17.   
18.         // Start our child containers, if any  
19.         //catalina構造server例項時,server.xml中如果存在host的子容器context,呼叫addChild方法  
20.         Container children[] = findChildren();  
21.         List<Future<Void>> results = new ArrayList<>();  
22.         for (int i = 0; i < children.length; i++) {  
23.             results.add(startStopExecutor.submit(new StartChild(children[i])));  
24.         }  
25.   
26.         boolean fail = false;  
27.         for (Future<Void> result : results) {  
28.             try {  
29.                 result.get();  
30.             } catch (Exception e) {  
31.                 log.error(sm.getString("containerBase.threadedStartFailed"), e);  
32.                 fail = true;  
33.             }  
34.   
35.         }  
36.         if (fail) {  
37.             throw new LifecycleException(  
38.                     sm.getString("containerBase.threadedStartFailed"));  
39.         }  
40.   
41.         // Start the Valves in our pipeline (including the basic), if any  
42.         //啟動host所持有的Pipeline元件  
43.         if (pipeline instanceof Lifecycle)  
44.             ((Lifecycle) pipeline).start();  
45.   
46.   
47.         // Start our thread  
48.         //開始執行緒,啟動後臺執行緒  
49.         threadStart();  
50.   
51.     }  
  1. 關注這一句results.add(startStopExecutor.submit(new StartChild(children[i])));這個地方用了執行緒的submit方法,看下面這段程式碼:
private static class StartChild implements Callable<Void> {  
2.    
3.         private Container child;  
4.    
5.         public StartChild(Container child) {  
6.             this.child = child;  
7.         }  
8.    
9.         @Override  
10.        public Void call() throws               LifecycleException {  
11.            child.start();/*在這個地方呼叫的*/  
12.            return null;  
13.        }  
14.    }  

這是StartChild類,可以看到他實現了callable介面,當執行緒使用submit方法時,call()方法會被呼叫,子容器將會呼叫start方法,即child.start(),在這個地方啟動了StandardHost。而且result是一個數組,遍歷啟動子容器,就是說一個容器可以啟動多個子容器,如一個StandardEngine可以有多個StandardHost。可以看到catalina的架構圖很明顯表明了這一點。
StandardHost原始碼分析(部分)

1.  protected synchronized void startInternal() throws LifecycleException {  
2.    
3.          // Set error report valve  
4.          //該類主要用於Tomcat發生異常時輸出錯誤頁面  
5.          String errorValve = getErrorReportValveClass();  
6.          //檢視pipleLine裡是否有error report valve  
7.          if ((errorValve != null) && (!errorValve.equals(""))) {  
8.              try {  
9.                  boolean found = false;  
10.                 Valve[] valves = getPipeline().getValves();  
11.                 for (Valve valve : valves) {  
12.                     if (errorValve.equals(valve.getClass().getName())) {  
13.                         found = true;  
14.                         break;  
15.                     }  
16.                 }  
17.                 if(!found) {  
18.                     Valve valve =  
19.                         (Valve) Class.forName(errorValve).getConstructor().newInstance();/*如果沒有找到利用反射建立物件*/  
20.                     getPipeline().addValve(valve);/*把valve加到管道里*/  
21.                 }  
22.             } catch (Throwable t) {  
23.                 ExceptionUtils.handleThrowable(t);  
24.                 log.error(sm.getString(  
25.                         "standardHost.invalidErrorReportValveClass",  
26.                         errorValve), t);  
27.             }  
28.         }  
29.         super.startInternal();//啟動虛擬主機,轉到了ContainBase  
30.     }  

可以看到,這個啟動方法裡面就只是做了兩件事:
1.添加了一個ErrorReportValve
2.呼叫containerBase.StartInternal()
關於containerBase.StartInternal()方法,前面已經添加了程式碼和註釋,不在贅述。
此時有兩種情況
1.catalina構造server例項時,server.xml中如果存在host的子容器context,呼叫addChild方法,此時直接呼叫StandardContext.Start()
2.沒有子容器context,觸發fireLifeCycleEvent(),轉到HostConfig。

把lifecycle的狀態改變了。而此時有監聽器,setState是基礎抽象類lifecycleBase的方法,我們看一下它的相關程式碼。
setState:

1.  protected synchronized void setState(LifecycleState state)  
2.              throws LifecycleException {  
3.          setStateInternal(state, null, true);  
4.      }  
在看這個setStateInternal:
1.  private synchronized void setStateInternal(LifecycleState state,  
2.              Object data, boolean check) throws LifecycleException {  
3.    
4.          if (log.isDebugEnabled()) {  
5.              log.debug(sm.getString("lifecycleBase.setState", this, state));  
6.          }  
7.    
8.          if (check) {  
9.              // Must have been triggered by one of the abstract methods (assume  
10.             // code in this class is correct)  
11.             // null is never a valid state  
12.             if (state == null) {  
13.                 invalidTransition("null");  
14.                 // Unreachable code - here to stop eclipse complaining about  
15.                 // a possible NPE further down the method  
16.                 return;  
17.             }  
18.   
19.             // Any method can transition to failed  
20.             // startInternal() permits STARTING_PREP to STARTING  
21.             // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to  
22.             // STOPPING  
23.             if (!(state == LifecycleState.FAILED ||  
24.                     (this.state == LifecycleState.STARTING_PREP &&  
25.                             state == LifecycleState.STARTING) ||  
26.                     (this.state == LifecycleState.STOPPING_PREP &&  
27.                             state == LifecycleState.STOPPING) ||  
28.                     (this.state == LifecycleState.FAILED &&  
29.                             state == LifecycleState.STOPPING))) {  
30.                 // No other transition permitted  
31.                 invalidTransition(state.name());  
32.             }  
33.         }  
34.   
35.         this.state = state;  
36.         String lifecycleEvent = state.getLifecycleEvent();  
37.         if (lifecycleEvent != null) {  
38.             fireLifecycleEvent(lifecycleEvent, data);  
39.         }  
40.     }  

可以在看到在最後觸發了這個生命週期事件。

1.  protected void fireLifecycleEvent(String type, Object data) {  
2.         LifecycleEvent event = new LifecycleEvent(this, type, data);  
3.         for (LifecycleListener listener : lifecycleListeners) {  
4.             listener.lifecycleEvent(event);  
5.         }  
6.     }  

在Digester建立物件時,listener為HostConfig。
接下來我們分析HostConfig的程式碼。
Tomcat8.5原始碼分析-HostConfig