本文主要介紹tomcat啓動過程當中,從server到context這一部分,主要涉及Lifecycle。java
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(); }
上面是Lifecycle接口,我把註釋都去掉了,接口定義中開始部分的static域(如:BEFORE_INIT_EVENT)是Lifecycle中支持的各類事件。以前咱們提到過,Lifecycle實現了一個觀察者模式,而上面這些事件就表明了tomcat中各個組件生命週期中的各個事件,當這些事件發生的時候,會通知感興趣的觀察者(LifecycleListener)。apache
Lifecycle在tomcat中被使用的不少,用來管理tomcat中各個組件的生命週期,以前的博文中咱們提到過的server、service、connector、engine、host、context等,他們都派生了Lifecycle接口。瀏覽器
Lifecycle中還聲明瞭幾個很重要的方法:init、start、stop、destroy。這幾個方法共同構成了組件的生命週期,init-初始化,start-啓動,stop-中止,destroy-銷燬。再看看上面的那些事件,實際上都是和這裏的幾個生命週期對應的,每一個生命週期XXX,都包括beforeXXX、XXX、afterXXX這三個事件。各個組件在tomcat啓動以後,到shutdown以前,就會經歷這樣的生命週期過程,從一開始初始化,最後被銷燬,中間可能會經歷start、stop、start、stop,起起落落。就像人誕生下來,無論中間過得多麼精彩,但最終的結果仍是會死亡。tomcat
Tomcat分紅不少的組件,這些組件須要分別啓動,咱們已經知道Lifecycle中聲明的start的方法就是用來完成這項工做的。這些組件都派生了Lifecycle接口,分別實現了Lifecycle裏的方法,也就擁有了管理本身生命週期(初始化、啓動、中止、銷燬)的能力。ide
接下來,咱們分析下各個組件是怎麼樣完成啓動過程的。ui
一個Server就表明了整個catalina servlet容器。所以,他的屬性,也能表明了整個servlet容器的特性。整個servlet的生命週期都由server控制。this
咱們在啓動tomcat的時候,首先會建立一個單例的server對象(其實是StandardServer對象,咱們以前提到過,一個tomcat中,只會有一個server),而後進行初始化(init),以後會調用server的start方法,用來啓動server。spa
咱們也提到過server中包含service,多是一個或者多個。code
/** * The set of Services associated with this Server. */ private Service services[] = new Service[0]; /** * Start nested components ({@link Service}s) and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Services synchronized (services) { for (int i = 0; i < services.length; i++) { services[i].start(); } } }
Server的start方法中,會調用上面的startInternal()方法。在startInternal()方法中,咱們能夠看到,server會將本身所擁有的service所有給start-啓動。component
Service中,有2種tomcat中最重要的組件:connector、container。Connector用來接收瀏覽器的請求,一個service中能夠有多個connector。Container主要有3種,分別是engine、host、context,service直接包含的是engine,engine包含host,host包含context,一個service只能有一個engine。
/** * The set of Connectors associated with this Service. */ protected Connector connectors[] = new Connector[0]; /** * The Container associated with this Service. (In the case of the * org.apache.catalina.startup.Embedded subclass, this holds the most * recently added Engine.) */ protected Container container = null; /** * Start nested components ({@link Executor}s, {@link Connector}s and * {@link Container}s) and implement the requirements of * {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { if(log.isInfoEnabled()) log.info(sm.getString("standardService.start.name", this.name)); setState(LifecycleState.STARTING); // Start our defined Container first if (container != null) { synchronized (container) { container.start(); } } synchronized (executors) { for (Executor executor: executors) { executor.start(); } } // Start our defined Connectors second synchronized (connectors) { 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); } } } }
同server同樣,service的start方法會調用他所擁有的container和connector的start方法。
如此一來,就至關於造成了一條鏈,server啓動的時候會去啓動service,service啓動的時候又會順道把container和connector啓動了。
剩下的就是container的啓動了,service啓動的container,實際上就是engine(StandardEngin)。
容器的start方法和server、service的有點不同,由於容器有一個包含關係,父容器包含子容器。父容器啓動的時候,會順道將本身全部的子容器啓動,頂層的容器是engine,他的子容器是一個或多個host,engine啓動的時候,會將他擁有的全部host啓動,而後host啓動的時候,又會將context啓動。
/** * Start this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void startInternal() throws LifecycleException { // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); logger = null; getLogger(); if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); if ((cluster != null) && (cluster instanceof Lifecycle)) ((Lifecycle) cluster).start(); Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Start our child containers, if any Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<Future<Void>>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); } boolean fail = false; for (Future<Void> result : results) { try { result.get(); } catch (Exception e) { log.error(sm.getString("containerBase.threadedStartFailed"), e); fail = true; } } if (fail) { throw new LifecycleException( sm.getString("containerBase.threadedStartFailed")); } // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start(); setState(LifecycleState.STARTING); // Start our thread threadStart(); }
如是, tomcat 啓動過程當中各個組件的啓動流程。