国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Tomcat源碼分析——生命周期管理

2019-11-14 15:28:57
字體:
來源:轉載
供稿:網友

前言

  從server.xml文件解析出來的各個對象都是容器,比如:Server、Service、Connector等。這些容器都具有新建、初始化完成、啟動、停止、失敗、銷毀等狀態。tomcat的實現提供了對這些容器的生命周期管理,本文將通過對Tomcat7.0的源碼閱讀,深入剖析這一過程。

Tomcat生命周期類接口設計

  我們先閱讀圖1,從中了解Tomcat涉及生命周期管理的主要類。

圖1  Tomcat生命周期類接口設計

這里對圖1中涉及的主要類作個簡單介紹:

  • 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?

  java管理程序擴展(java management extensions,簡稱JMX),是一個可以為Java應用程序或系統植入遠程管理功能的框架。為便于講解,我從網絡上找了一張JMX的架構,如圖2所示。

圖2  JMX架構

這里對圖2中三個分層進行介紹:

  • PRobe Level:負責資源的檢測(獲取信息),包含MBeans,通常也叫做Instrumentation Level。MX管理構件(MBean)分為四種形式,分別是標準管理構件(Standard MBean)、動態管理構件(Dynamic MBean)、開放管理構件(Open Mbean)和模型管理構件(Model MBean)。
  • Agent Level:即MBeanServer,是JMX的核心,負責連接Mbeans和應用程序。 
  • Remote Management Level:通過connectors和adaptors來遠程操作MBeanServer,常用的控制臺,例如JConsole、VisualVM等。

 容器

 Tomcat容器組成

  StandardServer、StandardService、Connector、StandardContext這些容器,彼此之間都有父子關系,每個容器都可能包含零個或者多個子容器,這些子容器可能存在不同類型或者相同類型的多個,如圖3所示。

圖3  Tomcat容器組成

 Tomcat容器狀態

  目前,Tomcat的容器具有以下狀態:

  • NEW:容器剛剛創建時,即在LifecycleBase實例構造完成時的狀態。
  • INITIALIZED:容器初始化完成時的狀態。
  • STARTING_PREP:容器啟動前的狀態。
  • STARTING:容器啟動過程中的狀態。
  • STARTED:容器啟動完成的狀態。
  • STOPPING_PREP:容器停止前的狀態。
  • STOPPING:容器停止過程中的狀態。
  • STOPPED:容器停止完成的狀態。
  • DESTROYED:容器銷毀后的狀態。
  • FAILED:容器啟動、停止過程中出現異常的狀態。
  • MUST_STOP:此狀態未使用。
  • MUST_DESTROY:此狀態未使用。

這些狀態都定義在枚舉類LifecycleState中。

事件與監聽

  每個容器由于繼承自LifecycleBase,當容器狀態發生變化時,都會調用fireLifecycleEvent方法,生成LifecycleEvent,并且交由此容器的事件監聽器處理。LifecycleBase的fireLifecycleEvent方法的實現見代碼清單1。

代碼清單1

    /**     * Allow sub classes to fire {@link Lifecycle} events.     *      * @param type  Event type     * @param data  Data associated with event.     */    protected void fireLifecycleEvent(String type, Object data) {        lifecycle.fireLifecycleEvent(type, data);    }

lifecycle的定義如下:

    /**     * Used to handle firing lifecycle events.     * TODO: Consider merging LifecycleSupport into this class.     */    private LifecycleSupport lifecycle = new LifecycleSupport(this);

LifecycleSupport的fireLifecycleEvent方法的實現,見代碼清單2。

代碼清單2

    /**     * Notify all lifecycle event listeners that a particular event has     * occurred for this Container.  The default implementation performs     * this notification synchronously using the calling thread. gja     *     * @param type Event type     * @param data Event data     */    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);    }

代碼清單2將事件通知給所有監聽當前容器的生命周期監聽器LifecycleListener,并調用LifecycleListener的lifecycleEvent方法。每個容器都維護這一個監聽器緩存,其實現如下:

    /**     * The set of registered LifecycleListeners for event notifications.     */    private LifecycleListener listeners[] = new LifecycleListener[0];

那么listeners中的監聽器是何時添加進來的呢?每個容器在新建、初始化、啟動,銷毀,被添加到父容器的過程中都會調用父類LifecycleBase的addLifecycleListener方法,addLifecycleListener的實現見代碼清單3。

 代碼清單3

    @Override    public void addLifecycleListener(LifecycleListener listener) {        lifecycle.addLifecycleListener(listener);    }

從代碼清單3看到,LifecycleBase的addLifecycleListener方法實際是對LifecycleSupport的addLifecycleListener方法的簡單代理,LifecycleSupport的addLifecycleListener方法的實現,見代碼清單4。

 代碼清單4

    /**     * Add a lifecycle event listener to this component.     *     * @param listener The listener to add     */    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;      }    }

在代碼清單2中,我們講過容器會最終調用每個對此容器感興趣的LifecycleListener的lifecycleEvent方法,那么LifecycleListener的lifecycleEvent方法會做些什么呢?為了簡單起見,我們以監聽器AprLifecycleListener為例,AprLifecycleListener的lifecycleEvent方法的實現,見代碼清單5。

代碼清單5

    /**     * Primary entry point for startup and shutdown events.     *     * @param event The event that has occurred     */    public void lifecycleEvent(LifecycleEvent event) {        if (Lifecycle.INIT_EVENT.equals(event.getType())) {            synchronized (lock) {                init();                if (aprAvailable) {                    try {                        initializeSSL();                    } catch (Throwable t) {                        log.info(sm.getString("aprListener.sslInit"));                    }                }            }        } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {            synchronized (lock) {                if (!aprAvailable) {                    return;                }                try {                    terminateAPR();                } catch (Throwable t) {                    log.info(sm.getString("aprListener.aprDestroy"));                }            }        }    }

 容器生命周期

  每個容器都會有自身的生命周期,其中也涉及狀態的遷移,以及伴隨的事件生成,本節詳細介紹Tomcat中的容器生命周期實現。所有容器的轉態轉換(如新疆、初始化、啟動、停止等)都是由外到內,由上到下進行,即先執行父容器的狀態轉換及相關操作,然后再執行子容器的轉態轉換,這個過程是層層迭代執行的。

容器新建

  所有容器在構造的過程中,都會首先對父類LifecycleBase進行構造。LifecycleBase中定義了所有容器的起始狀態為LifecycleState.NEW,代碼如下:

    /**     * The current state of the source component.     */    private volatile LifecycleState state = LifecycleState.NEW;

容器初始化

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

圖4  容器初始化時序圖

  圖4中所說的具體容器,實際就是LifecycleBase的具體實現類,目前LifecycleBase的類繼承體系如圖5所示。

圖5  LifecycleBase的類繼承體系

 

  根據圖4所示的初始化過程,我們對Tomcat的源碼進行分析,其處理步驟如下:

  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方法的實現見代碼清單6。

代碼清單6

    public synchronized final void init() throws LifecycleException {        if (!state.equals(LifecycleState.NEW)) {            invalidTransition(Lifecycle.INIT_EVENT);        }        initInternal();                setState(LifecycleState.INITIALIZED);    }

代碼清單6說明,只有當前容器的狀態處于LifecycleState.NEW的才可以被初始化,真正執行初始化的方法是initInternal,當初始化完畢,當前容器的狀態會被更改為LifecycleState.INITIALIZED。為了簡便起見,我們還是以StandardServer這個容器為例,StandardServer的initInternal方法的實現見代碼清單7。

代碼清單7

    @Override    protected void initInternal() throws LifecycleException {                super.initInternal();        // Register global String cache geng        // Note although the cache is global, if there are multiple Servers        // present in the JVM (may happen when embedding) then the same cache         // will be registered under multiple names        onameStringCache = register(new StringCache(), "type=StringCache");        // Register the MBeanFactory        onameMBeanFactory = register(new MBeanFactory(), "type=MBeanFactory");                // Register the naming resources        onameNamingResoucres = register(globalNamingResources,                "type=NamingResources");                // Initialize our defined Services        for (int i = 0; i < services.length; i++) {            services[i].init();        }    }

通過分析StandardServer的initInternal方法,其處理過程如下

步驟一 將當前容器注冊到JMX

  調用父類LifecycleBase的initInternal方法(見代碼清單8),為當前容器創建DynamicMBean,并注冊到JMX中。

 代碼清單8

    @Override    protected void initInternal() throws LifecycleException {                // If oname is not null then registration has already happened via jiaan        // preRegister().        if (oname == null) {            mserver = Registry.getRegistry(null, null).getMBeanServer();                        oname = register(this, getObjectNameKeyProperties());        }    }

StandardServer實現的getObjectNameKeyProperties方法如下:

    @Override    protected final String getObjectNameKeyProperties() {        return "type=Server";    }

LifecycleBase的register方法(見代碼清單9)會為當前容器創建對應的注冊名稱,以StandardServer為例,getDomain默認返回Catalina,因此StandardServer的JMX注冊名稱默認為Catalina:type=Server,真正的注冊在registerComponent方法中實現。

代碼清單9

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

Registry的registerComponent方法會為當前容器(如StandardServer)創建DynamicMBean,并且注冊到MBeanServer,見代碼清單10。

代碼清單10

    /** Register a component      * XXX make it private      *      * @param bean     * @param oname     * @param type     * @throws Exception     */     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;        }    }

步驟二 將StringCache、MBeanFactory、globalNamingResources注冊到JMX

  從代碼清單7中已經列出。其中StringCache的注冊名為Catalina:type=StringCache,MBeanFactory的注冊名為Catalina:type=MBeanFactory,globalNamingResources的注冊名為Catalina:type=NamingResources。

步驟三 初始化子容器

  從代碼清單7中看到StandardServer主要對Service子容器進行初始化,默認是StandardService。

 

注意:個別容器并不完全遵循以上的初始化過程,比如ProtocolHandler作為Connector的子容器,其初始化過程并不是由Connector的initInternal方法調用的,而是與啟動過程一道被Connector的startInternal方法所調用。

容器啟動

  每個容器的start方法是自身啟動的入口,其啟動過程如圖6所示。

圖6  容器啟動時序圖

 

  根據圖6所示的啟動過程,我們對Tomcat的源碼進行分析,其處理步驟如下:

  1. 調用方調用容器父類LifecycleBase的start方法,LifecycleBase的start方法主要完成一些所有容器公共抽象出來的動作;
  2. LifecycleBase的start方法先將容器狀態改為LifecycleState.STARTING_PREP,然后調用具體容器的startInternal方法實現,此startInternal方法用于對容器本身真正的初始化;
  3. 具體容器的startInternal方法會將容器狀態改為LifecycleState.STARTING,容器如果有子容器,會調用子容器的start方法啟動子容器;
  4. 容器啟動完畢,LifecycleBase會將容器的狀態更改為啟動完畢,即LifecycleState.STARTED。

  現在對容器啟動的源碼進行分析,start方法的實現見代碼清單11。

代碼清單11

    @Override    public synchronized final 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.INITIALIZED) &&                !state.equals(LifecycleState.STOPPED)) {            invalidTransition(Lifecycle.BEFORE_START_EVENT);        }        setState(LifecycleState.STARTING_PREP);        try {            startInternal();        } catch (LifecycleException e) {            setState(LifecycleState.FAILED);            throw e;        }        if (state.equals(LifecycleState.FAILED) ||                state.equals(LifecycleState.MUST_STOP)) {            stop();        } else {            // Shouldn't be necessary but acts as a check that sub-classes are            // doing what they are supposed to.            if (!state.equals(LifecycleState.STARTING)) {                invalidTransition(Lifecycle.AFTER_START_EVENT);            }                        setState(LifecycleState.STARTED);        }    }

代碼清單11說明在真正啟動容器之前需要做2種檢查:

  1. 如果當前容器已經處于啟動過程(即容器狀態為LifecycleState.STARTING_PREP、LifecycleState.STARTING、LifecycleState.STARTED)中,則會產生并且用日志記錄LifecycleException異常并退出。
  2. 如果容器依然處于LifecycleState.NEW狀態,則在啟動之前,首先確保初始化完畢。

代碼清單11還說明啟動容器完畢后,需要做1種檢查,即如果容器啟動異常導致容器進入LifecycleState.FAILED或者LifecycleState.MUST_STOP狀態,則需要調用stop方法停止容器。

  現在我們重點分析startInternal方法,還是以StandardServer為例,其startInternal的實現見代碼清單12所示。

代碼清單12

    @Override    protected void startInternal() throws LifecycleException {        fireLifecycleEvent(CONFIGURE_START_EVENT, null);        setState(LifecycleState.STARTING);        // Start our defined Services        synchronized (services) {            for (int i = 0; i < services.length; i++) {                services[i].start();            }        }    }

  從代碼清單12看到StandardServer的啟動由以下步驟組成:

  1. 產生CONFIGURE_START_EVENT事件;
  2. 將自身狀態更改為LifecycleState.STARTING;
  3. 調用子容器Service(默認為StandardService)的start方法啟動子容器。

除了初始化、啟動外,各個容器還有停止和銷毀的生命周期,其原理與初始化、啟動類似,本文不再贅述,有興趣的讀者可以自行研究。

  Tomcat啟動完畢后,打開Java visualVM,打開Tomcat進程監控,給visualVM安裝MBeans插件后,選擇MBeans標簽頁可以對Tomcat所有注冊到JMX中的對象進行管理,比如StandardService就向JMX暴露了start和stop等方法,這樣管理員就可以動態管理Tomcat,如圖7所示。

圖7  使用JMX動態管理Tomcat

總結

  Tomcat通過將內部所有組件都抽象為容器,為容器提供統一的生命周期管理,各個子容器只需要關心各自的具體實現,這便于Tomcat以后擴展更多的容器,對于研究或者學習Tomcat的人來說,其設計清晰易懂。

 

如需轉載,請標明本文作者及出處——作者:jiaan.gja,本文原創首發:博客園,原文鏈接:http://m.survivalescaperooms.com/jiaan-geng/p/4864501.html

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 玉龙| 哈密市| 惠水县| 陇西县| 甘孜| 遂川县| 库尔勒市| 南郑县| 乐陵市| 宜君县| 泗水县| 汉川市| 甘孜县| 广安市| 察雅县| 谢通门县| 信阳市| 樟树市| 昌江| 湛江市| 绥滨县| 拉孜县| 白山市| 昭通市| 平遥县| 宾川县| 嘉兴市| 洛隆县| 南华县| 大厂| 海林市| 曲周县| 磐石市| 镇康县| 岱山县| 南岸区| 宝鸡市| 阿瓦提县| 神农架林区| 亚东县| 青川县|