想必你們都知道,從server.xml文件解析出來的各個對象都是容器,好比:Server、Service、Connector等。這些容器都具備新建、初始化完成、啓動、中止、失敗、銷燬等狀態。Tomcat的實現機制是經過實現org.apache.catalina.Lifecycle接口來管理。apache
定義了容器生命週期、容器狀態轉換及容器狀態遷移事件的監聽器註冊和移除等主要接口。代碼清單:服務器
public interface Lifecycle { public static final String BEFORE_INIT_EVENT = "before_init"; public static final String AFTER_INIT_EVENT = "after_init"; public static final String START_EVENT = "start"; public static final String BEFORE_START_EVENT = "before_start"; public static final String AFTER_START_EVENT = "after_start"; public static final String STOP_EVENT = "stop"; public static final String BEFORE_STOP_EVENT = "before_stop"; public static final String AFTER_STOP_EVENT = "after_stop"; public static final String AFTER_DESTROY_EVENT = "after_destroy"; public static final String BEFORE_DESTROY_EVENT = "before_destroy"; public static final String PERIODIC_EVENT = "periodic"; public static final String CONFIGURE_START_EVENT = "configure_start"; public static final String CONFIGURE_STOP_EVENT = "configure_stop"; public void addLifecycleListener(LifecycleListener listener); public LifecycleListener[] findLifecycleListeners(); public void removeLifecycleListener(LifecycleListener listener); public void init() throws LifecycleException; public void start() throws LifecycleException; public void stop() throws LifecycleException; public void destroy() throws LifecycleException; public LifecycleState getState(); public String getStateName(); public interface SingleUse { } }
其中,最重要的方法時start和stop方法。父組件經過這兩個方法來啓動/關閉該組件。addLifecycleListener,findLifecycleListeners,removeLifecycleListener三個方法用於向組件註冊/查找/刪除監聽器。當事件發生時,會觸發監聽器。接口中還定義了相關事件。網絡
下面從一幅圖來了解Tomcat涉及生命週期管理的主要類:app
從上圖能夠看出ContainerBase、StandardServer、StandardService、WebappLoader、Connector、StandardContext、StandardEngine、StandardHost、StandardWrapper等容器都繼承了LifecycleMBeanBase,所以這些容器都具備了一樣的生命週期並能夠經過JMX進行管理。框架
JMX(Java Management Extensions,即Java管理擴展)是一個爲應用程序、設備、系統等植入管理功能的框架。JMX能夠跨越一系列異構操做系統平臺、系統體系結構和網絡傳輸協議,靈活的開發無縫集成的系統、網絡和服務管理應用。運維
JMX體系結構分爲如下四個層次:dom
設備層ui
設備層(Instrumentation Level):主要定義了信息模型。在JMX中,各類管理對象以管理構件的形式存在,須要管理時,向MBean服務器進行註冊。該層還定義了通知機制以及一些輔助元數據類。this
代理層網絡傳輸協議
代理層(Agent Level):主要定義了各類服務以及通訊模型。該層的核心是一個MBean服務器,全部的管理構件都須要向它註冊,才能被管理。註冊在MBean服務器上管理構件並不直接和遠程應用程序進行通訊,它們經過協議適配器和鏈接器進行通訊。而協議適配器和鏈接器也以管理構件的形式向MBean服務器註冊才能提供相應的服務。
分佈服務層
分佈服務層(Distributed Service Level):主要定義了能對代理層進行操做的管理接口和構件,這樣管理者就能夠操做代理。然而,當前的JMX規範並無給出這一層的具體規範。
附加管理協議API
定義的API主要用來支持當前已經存在的網絡管理協議,如SNMP、TMN、CIM/WBEM等。
每一個容器因爲繼承自LifecycleBase,當容器狀態發生變化時,都會調用fireLifecycleEvent方法,生成LifecycleEvent,而且交由此容器的事件監聽器處理。
LifecycleBase的fireLifecycleEvent方法的實現:
protected void fireLifecycleEvent(String type, Object data) { lifecycle.fireLifecycleEvent(type, data); } //lifecycle定義 private LifecycleSupport lifecycle = new LifecycleSupport(this); //LifecycleSupport的fireLifecycleEvent方法的實現 public void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); LifecycleListener interested[] = listeners; for (int i = 0; i < interested.length; i++) interested[i].lifecycleEvent(event); }
而後將事件通知給全部監聽當前容器的生命週期監聽器LifecycleListener,並調用LifecycleListener的lifecycleEvent方法。
那麼監聽器LifecycleListener是什麼時候註冊進來的?其實每一個容器在新建、初始化、啓動,銷燬,被添加到父容器的過程當中都會調用父類LifecycleBase的addLifecycleListener方法:
public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); }
LifecycleBase的addLifecycleListener方法實際是對LifecycleSupport的addLifecycleListener方法的簡單代理,LifecycleSupport的addLifecycleListener方法的實現:
public void addLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) { LifecycleListener results[] = new LifecycleListener[listeners.length + 1]; for (int i = 0; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener; listeners = results; } }
容器會最終調用每一個對此容器感興趣的LifecycleListener的lifecycleEvent方法,那麼LifecycleListener的lifecycleEvent方法會作些什麼呢?爲了簡單起見,咱們以監聽器JasperListener爲例,JasperListener的lifecycleEvent方法的實現:
public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) { try { // Set JSP factory Class.forName("org.apache.jasper.compiler.JspRuntimeContext", true, this.getClass().getClassLoader()); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // Should not occur, obviously log.warn("Couldn't initialize Jasper", t); } // Another possibility is to do directly: // JspFactory.setDefaultFactory(new JspFactoryImpl()); } }
StandardServer、StandardService、Connector、StandardContext這些容器,彼此之間都有父子關係,每一個容器均可能包含零個或者多個子容器,這些子容器可能存在不一樣類型或者相同類型的多個。在一個容器建立成功後,會有如下狀態:
NEW:容器剛剛建立時,即在LifecycleBase實例構造完成時的狀態。
INITIALIZED:容器初始化完成時的狀態。
STARTING_PREP:容器啓動前的狀態。
STARTING:容器啓動過程當中的狀態。
STARTED:容器啓動完成的狀態。
STOPPING_PREP:容器中止前的狀態。
STOPPING:容器中止過程當中的狀態。
STOPPED:容器中止完成的狀態。
DESTROYED:容器銷燬後的狀態。
FAILED:容器啓動、中止過程當中出現異常的狀態。
MUST_STOP:此狀態未使用。
MUST_DESTROY:此狀態未使用。
這些狀態都定義在枚舉類LifecycleState中。代碼詳單:
public enum LifecycleState { NEW(false, null), INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT), INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT), STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT), STARTING(true, Lifecycle.START_EVENT), STARTED(true, Lifecycle.AFTER_START_EVENT), STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT), STOPPING(false, Lifecycle.STOP_EVENT), STOPPED(false, Lifecycle.AFTER_STOP_EVENT), DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT), DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT), FAILED(false, null), /** * @deprecated Unused. Will be removed in Tomcat 9.0.x. The state transition * checking in {[@link](http://my.oschina.net/u/393) org.apache.catalina.util.LifecycleBase} * makes it impossible to use this state. The intended behaviour * can be obtained by setting the state to * {[@link](http://my.oschina.net/u/393) LifecycleState#FAILED} in * <code>LifecycleBase.startInternal()</code> */ @Deprecated MUST_STOP(true, null), /** * @deprecated Unused. Will be removed in Tomcat 9.0.x. The state transition * checking in {@link org.apache.catalina.util.LifecycleBase} * makes it impossible to use this state. The intended behaviour * can be obtained by implementing {@link Lifecycle.SingleUse}. */ @Deprecated MUST_DESTROY(false, null); private final boolean available; private final String lifecycleEvent; private LifecycleState(boolean available, String lifecycleEvent) { this.available = available; this.lifecycleEvent = lifecycleEvent; } /** * May the public methods other than property getters/setters and lifecycle * methods be called for a component in this state? It returns * <code>true</code> for any component in any of the following states: * <ul> * <li>{@link #STARTING}</li> * <li>{@link #STARTED}</li> * <li>{@link #STOPPING_PREP}</li> * <li>{@link #MUST_STOP}</li> * </ul> */ public boolean isAvailable() { return available; } /** * */ public String getLifecycleEvent() { return lifecycleEvent; } }
每一個容器都會有自身的生命週期,其中也涉及狀態的遷移,以及伴隨的事件生成。全部容器的狀態轉換(如新建、初始化、啓動、中止等)都是由外到內,由上到下進行,即先執行父容器的狀態轉換及相關操做,而後再執行子容器的轉態轉換,這個過程是層層迭代執行的。
全部容器在構造的過程當中,都會首先對父類LifecycleBase進行構造。LifecycleBase中定義了全部容器的起始狀態爲LifecycleState.NEW。
private volatile LifecycleState state = LifecycleState.NEW;
每一個容器的init方法是自身初始化的入口,其初始化過程如圖所示:
調用方調用容器父類LifecycleBase的init方法,LifecycleBase的init方法主要完成一些全部容器公共抽象出來的動做;
LifecycleBase的init方法調用具體容器的initInternal方法實現,此initInternal方法用於對容器自己真正的初始化;
具體容器的initInternal方法調用父類LifecycleMBeanBase的initInternal方法實現,此initInternal方法用於將容器託管到JMX,便於運維管理;
LifecycleMBeanBase的initInternal方法調用自身的register方法,將容器做爲MBean註冊到MBeanServer;
容器若是有子容器,會調用子容器的init方法;
容器初始化完畢,LifecycleBase會將容器的狀態更改成初始化完畢,即LifecycleState.INITIALIZED。
init方法的實現
public final synchronized void init() throws LifecycleException { if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } setStateInternal(LifecycleState.INITIALIZING, null, false); try { initInternal();//調用具體容器的initInternal方法實現 } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException( sm.getString("lifecycleBase.initFail",toString()), t); } setStateInternal(LifecycleState.INITIALIZED, null, false); }
只有當前容器的狀態處於LifecycleState.NEW的才能夠被初始化,真正執行初始化的方法是initInternal,當初始化完畢,當前容器的狀態會被更改成LifecycleState.INITIALIZED。以StandardService這個容器爲例舉例分析,StandardService容器的initInternal方法實現:
protected void initInternal() throws LifecycleException { super.initInternal(); if (container != null) { container.init(); } // Initialize any Executors for (Executor executor : findExecutors()) { if (executor instanceof LifecycleMBeanBase) { ((LifecycleMBeanBase) executor).setDomain(getDomain()); } executor.init(); } // Initialize our defined Connectors synchronized (connectorsLock) { for (Connector connector : connectors) { try { connector.init(); } catch (Exception e) { String message = sm.getString( "standardService.connector.initFailed", connector); log.error(message, e); if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) throw new LifecycleException(message); } } } }
其處理過程:
a、調用父類LifecycleBase的initInternal方法,爲當前容器建立DynamicMBean,並註冊到JMX中。
protected void initInternal() throws LifecycleException { // If oname is not null then registration has already happened via // preRegister(). if (oname == null) { mserver = Registry.getRegistry(null, null).getMBeanServer(); oname = register(this, getObjectNameKeyProperties()); } } //getObjectNameKeyProperties()方法 public final String getObjectNameKeyProperties() { return "type=Service"; }
LifecycleBase的register方法會爲當前容器建立對應的註冊名稱,以StandardService爲例,getDomain默認返回Catalina,所以StandardService的JMX註冊名稱默認爲Catalina:type=Service,真正的註冊在registerComponent方法中實現。
//register方法 protected final ObjectName register(Object obj, String objectNameKeyProperties) { // Construct an object name with the right domain StringBuilder name = new StringBuilder(getDomain()); name.append(':'); name.append(objectNameKeyProperties); ObjectName on = null; try { on = new ObjectName(name.toString()); Registry.getRegistry(null, null).registerComponent(obj, on, null); } catch (MalformedObjectNameException e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } catch (Exception e) { log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name), e); } return on; } //registerComponent方法 public void registerComponent(Object bean, ObjectName oname, String type) throws Exception { if( log.isDebugEnabled() ) { log.debug( "Managed= "+ oname); } if( bean ==null ) { log.error("Null component " + oname ); return; } try { if( type==null ) { type=bean.getClass().getName(); } ManagedBean managed = findManagedBean(bean.getClass(), type); // The real mbean is created and registered DynamicMBean mbean = managed.createMBean(bean); if( getMBeanServer().isRegistered( oname )) { if( log.isDebugEnabled()) { log.debug("Unregistering existing component " + oname ); } getMBeanServer().unregisterMBean( oname ); } getMBeanServer().registerMBean( mbean, oname); } catch( Exception ex) { log.error("Error registering " + oname, ex ); throw ex; } }
Registry的registerComponent方法會爲當前容器(如StandardService)建立DynamicMBean,而且註冊到MBeanServer中。
b、將StringCache、MBeanFactory、globalNamingResources註冊到JMX
其中StringCache的註冊名爲Catalina:type=StringCache,MBeanFactory的註冊名爲Catalina:type=MBeanFactory,globalNamingResources的註冊名爲Catalina:type=NamingResources(如StandardService則爲:Catalina:type=Service)
c、初始化子容器
主要對Service子容器進行初始化,默認是StandardService。
注意:個別容器並不徹底遵循以上的初始化過程,好比ProtocolHandler做爲Connector的子容器,其初始化過程並非由Connector的initInternal方法調用的,而是與啓動過程一道被Connector的startInternal方法所調用。
每一個容器的start方法是自身啓動的入口
調用方調用容器父類LifecycleBase的start方法,LifecycleBase的start方法主要完成一些全部容器公共抽象出來的動做;
LifecycleBase的start方法先將容器狀態改成LifecycleState.STARTING_PREP,而後調用具體容器的startInternal方法實現,此startInternal方法用於對容器自己真正的初始化;
具體容器的startInternal方法會將容器狀態改成LifecycleState.STARTING,容器若是有子容器,會調用子容器的start方法啓動子容器;
容器啓動完畢,LifecycleBase會將容器的狀態更改成啓動完畢,即LifecycleState.STARTED。
//LifecycleBase的start方法 public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)) { stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { startInternal(); } catch (Throwable t) { // This is an 'uncontrolled' failure so put the component into the // FAILED state and throw an exception. ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t); } if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } }
在真正啓動容器以前須要作2種檢查:
若是當前容器已經處於啓動過程(即容器狀態爲LifecycleState.STARTING_PREP、LifecycleState.STARTING、LifecycleState.STARTED)中,則會產生而且用日誌記錄LifecycleException異常並退出。 若是容器依然處於LifecycleState.NEW狀態,則在啓動以前,首先確保初始化完畢。
啓動容器完畢後,須要作1種檢查: 即若是容器啓動異常致使容器進入LifecycleState.FAILED或者LifecycleState.MUST_STOP狀態,則須要調用stop方法中止容器。
以StandardService爲例,其startInternal的實現:
protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); setState(LifecycleState.STARTING);//將自身狀態更改成LifecycleState.STARTING; // Start our defined Container first if (container != null) { synchronized (container) { container.start();//調用子容器Service的start方法啓動子容器。 } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } // Start our defined Connectors second synchronized (connectorsLock) { for (Connector connector: connectors) { try { // If it has already failed, don't try and start it if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } catch (Exception e) { log.error(sm.getString( "standardService.connector.startFailed", connector), e); } } } }
除了初始化、啓動外,各個容器還有中止和銷燬的生命週期,其原理與初始化、啓動相似。
Tomcat經過將內部全部組件都抽象爲容器,爲容器提供統一的生命週期管理,各個子容器只須要關心各自的具體實現,這便於Tomcat之後擴展更多的容器。