亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

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

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://www.49028c.com/jiaan-geng/p/4864501.html

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情影音先锋| 91久久精品国产91性色| 亚洲第一男人天堂| 4p变态网欧美系列| 欧美精品激情blacked18| 欧美乱妇高清无乱码| 国产精品福利小视频| 成人精品久久一区二区三区| 国产精品一区二区电影| 欧美性猛交xxxx黑人| 日韩精品在线私人| 欧美成人午夜剧场免费观看| 日韩一级裸体免费视频| 亚洲理论在线a中文字幕| 欧美精品在线网站| 日本午夜精品理论片a级appf发布| 成人高h视频在线| 操日韩av在线电影| 亚洲欧洲激情在线| 2023亚洲男人天堂| 国产精品高潮在线| 欧美精品videos另类日本| 日韩中文在线视频| 美女扒开尿口让男人操亚洲视频网站| 久久手机免费视频| 国产日韩精品综合网站| 欧美特黄级在线| 91高清免费在线观看| 亚洲电影免费在线观看| 久久av红桃一区二区小说| 亚洲国产成人一区| 深夜福利日韩在线看| 91成人天堂久久成人| 国产亚洲在线播放| 国产在线98福利播放视频| 在线观看国产精品日韩av| 久久久中精品2020中文| 久99九色视频在线观看| 在线视频日韩精品| 91爱爱小视频k| 国产精品久久久久久久电影| 国产精品久久久久久久久久新婚| 午夜精品美女自拍福到在线| 亚洲欧美综合另类中字| 国产一区二区三区欧美| 久久全国免费视频| 久久99国产精品久久久久久久久| 日韩美女av在线免费观看| 中文字幕精品一区久久久久| 国产精品久久久久久av福利| 欧美成人免费一级人片100| 成人有码在线播放| 国产精品扒开腿做爽爽爽视频| 久久精品亚洲国产| 欧美午夜xxx| 亚洲午夜国产成人av电影男同| 亚洲欧美精品一区| 2025国产精品视频| 成人免费网站在线观看| 日韩av第一页| 美女福利精品视频| 亚洲视频电影图片偷拍一区| 久久久噜久噜久久综合| 久久精品亚洲国产| 欧美激情乱人伦| 97视频免费在线看| 国产成人高清激情视频在线观看| 欧美丝袜美女中出在线| 日韩精品极品视频免费观看| 国产一区二区在线免费视频| 美女福利视频一区| 久久久久久成人精品| 成人深夜直播免费观看| 中文字幕日韩精品在线观看| 这里只有视频精品| 久久国产精品99国产精| 热门国产精品亚洲第一区在线| 亚洲欧美日韩爽爽影院| 最近中文字幕2019免费| 国产精品一二三视频| 久久人人爽亚洲精品天堂| 欧美日韩成人在线播放| 大荫蒂欧美视频另类xxxx| 97超级碰在线看视频免费在线看| 777777777亚洲妇女| 国产亚洲欧洲高清一区| 欧美精品激情blacked18| 欧美激情一区二区久久久| 欧美大片免费观看| 成人精品一区二区三区电影黑人| 精品电影在线观看| 国产综合久久久久久| 亚洲男人天堂2023| 国产亚洲激情在线| 国产欧美在线看| 91精品国产电影| 欧美在线不卡区| 亚洲美女喷白浆| 亚洲天堂一区二区三区| 国产精品揄拍一区二区| 亚洲美女性生活视频| 欧美国产日韩视频| 欧美精品videossex88| 国产精品人人做人人爽| 国产亚洲精品一区二区| 国产精品久久在线观看| 国产视频久久久久久久| 韩国精品美女www爽爽爽视频| 成人精品在线视频| 欧美激情va永久在线播放| 亚洲石原莉奈一区二区在线观看| 欧美国产欧美亚洲国产日韩mv天天看完整| 超薄丝袜一区二区| 国产成人+综合亚洲+天堂| 中文字幕日韩欧美| 亚洲性生活视频| 欧美电影在线免费观看网站| 亚洲国产小视频| 色www亚洲国产张柏芝| 国产综合视频在线观看| 韩国福利视频一区| 日本高清+成人网在线观看| 91日韩在线播放| 久久久久久久久爱| 欧美激情中文字幕乱码免费| 96sao精品视频在线观看| 97精品久久久| 亚洲综合中文字幕在线| 日本韩国欧美精品大片卡二| 国产一区二区日韩精品欧美精品| 日韩欧美国产一区二区| 欧美在线一级视频| 少妇激情综合网| 国产精品男人的天堂| 成人精品久久久| 中文字幕欧美日韩精品| 国产专区精品视频| 中日韩午夜理伦电影免费| 欧洲日本亚洲国产区| 久久久久久久久久国产精品| 国产中文字幕亚洲| 国产成人在线亚洲欧美| 亚洲欧美日韩精品久久亚洲区| 中文字幕欧美精品在线| 久久中文精品视频| 欧美日韩亚洲激情| 九色91av视频| 国内精品免费午夜毛片| 欧美www在线| 日韩免费精品视频| 欧美日韩国产在线| 亚洲福利视频久久| 日韩国产高清污视频在线观看| 国产精品久久久久免费a∨大胸| 精品国产成人av| 日韩欧美aⅴ综合网站发布| 美女视频久久黄| 久久69精品久久久久久久电影好| 在线观看成人黄色| 96pao国产成视频永久免费| 久久av中文字幕| 日韩女优人人人人射在线视频| 欧美性感美女h网站在线观看免费| 欧美亚洲另类视频|