tomcat的啓動過程與Lifecycle

本文主要介紹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

Lifecycletomcat中被使用的不少,用來管理tomcat中各個組件的生命週期,以前的博文中咱們提到過的serverserviceconnectorenginehostcontext等,他們都派生了Lifecycle接口。瀏覽器

Lifecycle中還聲明瞭幾個很重要的方法:initstartstopdestroy。這幾個方法共同構成了組件的生命週期,init-初始化,start-啓動,stop-中止,destroy-銷燬。再看看上面的那些事件,實際上都是和這裏的幾個生命週期對應的,每一個生命週期XXX,都包括beforeXXXXXXafterXXX這三個事件。各個組件在tomcat啓動以後,到shutdown以前,就會經歷這樣的生命週期過程,從一開始初始化,最後被銷燬,中間可能會經歷startstopstartstop,起起落落。就像人誕生下來,無論中間過得多麼精彩,但最終的結果仍是會死亡。tomcat

Tomcat分紅不少的組件,這些組件須要分別啓動,咱們已經知道Lifecycle中聲明的start的方法就是用來完成這項工做的。這些組件都派生了Lifecycle接口,分別實現了Lifecycle裏的方法,也就擁有了管理本身生命週期(初始化、啓動、中止、銷燬)的能力。ide

接下來,咱們分析下各個組件是怎麼樣完成啓動過程的。ui

一個Server就表明了整個catalina servlet容器。所以,他的屬性,也能表明了整個servlet容器的特性。整個servlet的生命週期都由server控制。this

咱們在啓動tomcat的時候,首先會建立一個單例的server對象(其實是StandardServer對象,咱們以前提到過,一個tomcat中,只會有一個server),而後進行初始化(init),以後會調用serverstart方法,用來啓動serverspa

咱們也提到過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();
            }
        }
    }

Serverstart方法中,會調用上面的startInternal()方法。在startInternal()方法中,咱們能夠看到,server會將本身所擁有的service所有給start-啓動。component

Service中,有2tomcat中最重要的組件:connectorcontainerConnector用來接收瀏覽器的請求,一個service中能夠有多個connectorContainer主要有3種,分別是enginehostcontextservice直接包含的是engineengine包含hosthost包含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同樣,servicestart方法會調用他所擁有的containerconnectorstart方法。

如此一來,就至關於造成了一條鏈,server啓動的時候會去啓動serviceservice啓動的時候又會順道把containerconnector啓動了。

剩下的就是container的啓動了,service啓動的container,實際上就是engineStandardEngin)。

容器的start方法和serverservice的有點不同,由於容器有一個包含關係,父容器包含子容器。父容器啓動的時候,會順道將本身全部的子容器啓動,頂層的容器是engine,他的子容器是一個或多個hostengine啓動的時候,會將他擁有的全部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 啓動過程當中各個組件的啓動流程。
相關文章
相關標籤/搜索