Tomcat源碼學習(六)--Tomcat_7.0.70 生命週期管理

想必你們都知道,從server.xml文件解析出來的各個對象都是容器,好比:Server、Service、Connector等。這些容器都具備新建、初始化完成、啓動、中止、失敗、銷燬等狀態。Tomcat的實現機制是經過實現org.apache.catalina.Lifecycle接口來管理。apache

Tomcat--Lifecycle接口

定義了容器生命週期、容器狀態轉換及容器狀態遷移事件的監聽器註冊和移除等主要接口。代碼清單:服務器

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

  • Lifecycle:定義了容器生命週期、容器狀態轉換及容器狀態遷移事件的監聽器註冊和移除等主要接口;
  • LifecycleBase:做爲Lifecycle接口的抽象實現類,運用抽象模板模式將全部容器的生命週期及狀態轉換銜接起來,此外還提供了生成LifecycleEvent事件的接口;
  • LifecycleSupport:提供有關LifecycleEvent事件的監聽器註冊、移除,而且使用經典的監聽器模式,實現事件生成後觸打監聽器的實現;
  • MBeanRegistration:Java jmx框架提供的註冊MBean的接口,引入此接口是爲了便於使用JMX提供的管理功能;
  • LifecycleMBeanBase:Tomcat提供的對MBeanRegistration的抽象實現類,運用抽象模板模式將全部容器統一註冊到JMX;

從上圖能夠看出ContainerBase、StandardServer、StandardService、WebappLoader、Connector、StandardContext、StandardEngine、StandardHost、StandardWrapper等容器都繼承了LifecycleMBeanBase,所以這些容器都具備了一樣的生命週期並能夠經過JMX進行管理。框架

什麼是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等。

Tomcat--事件、監聽

每一個容器因爲繼承自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());
    }

}

Tomcat--容器生命週期

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;
    }
}

每一個容器都會有自身的生命週期,其中也涉及狀態的遷移,以及伴隨的事件生成。全部容器的狀態轉換(如新建、初始化、啓動、中止等)都是由外到內,由上到下進行,即先執行父容器的狀態轉換及相關操做,而後再執行子容器的轉態轉換,這個過程是層層迭代執行的。

Tomcat容器生命週期----新建

全部容器在構造的過程當中,都會首先對父類LifecycleBase進行構造。LifecycleBase中定義了全部容器的起始狀態爲LifecycleState.NEW。

private volatile LifecycleState state = LifecycleState.NEW;

Tomcat容器生命週期----初始化

每一個容器的init方法是自身初始化的入口,其初始化過程如圖所示:

  1. 調用方調用容器父類LifecycleBase的init方法,LifecycleBase的init方法主要完成一些全部容器公共抽象出來的動做;

  2. LifecycleBase的init方法調用具體容器的initInternal方法實現,此initInternal方法用於對容器自己真正的初始化;

  3. 具體容器的initInternal方法調用父類LifecycleMBeanBase的initInternal方法實現,此initInternal方法用於將容器託管到JMX,便於運維管理;

  4. LifecycleMBeanBase的initInternal方法調用自身的register方法,將容器做爲MBean註冊到MBeanServer;

  5. 容器若是有子容器,會調用子容器的init方法;

  6. 容器初始化完畢,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方法所調用。

Tomcat容器生命週期----容器啓動

每一個容器的start方法是自身啓動的入口

  1. 調用方調用容器父類LifecycleBase的start方法,LifecycleBase的start方法主要完成一些全部容器公共抽象出來的動做;

  2. LifecycleBase的start方法先將容器狀態改成LifecycleState.STARTING_PREP,而後調用具體容器的startInternal方法實現,此startInternal方法用於對容器自己真正的初始化;

  3. 具體容器的startInternal方法會將容器狀態改成LifecycleState.STARTING,容器若是有子容器,會調用子容器的start方法啓動子容器;

  4. 容器啓動完畢,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之後擴展更多的容器。

相關文章
相關標籤/搜索