1. 程式人生 > >深入分析理解Tomcat體系結構-讀書筆記

深入分析理解Tomcat體系結構-讀書筆記

container 上層 method nec tor contex running 詳細 adapt

Tomcat整體結構

技術分享圖片

  由上圖可知Tomcat的頂層容器是Server,而且一個Tomcat對應一個Server,一個server有多個service提供服務.service包含兩個重要組件:Connector和Container.這個後面詳細講解.這個Server由誰來管理呢?當然是Catalina了,她是tomcat的管理類,她的三個方法load,start,stop分別用來管理整個服務器的生命周期.

Load方法:Load方法根據conf/server.xml文件創建Server並調用Server的init方法進行初始化.Server的init方法調用所有service的init方法,service的init方法調用所有Connector和Container的init方法.整個初始化工作就完成了.

Start方法:用於啟動服務,類似init,也是逐層進行啟動.

Stop方法:用於關閉服務,類似init,也是逐層調用關閉.

最後,CatAlina中的await方法非常重要,這個方法調用Server中的await方法,這個方法的作用就是進入一個循環,保持主線程不退出.

Tomcat組件啟動過程

技術分享圖片

Bootstrap的啟動過程

Tomcat啟動的入口方法就是Bootstrap中的main方法,代碼如下:

技術分享圖片
 public static void main(String args[]) {
        if (daemon == null) {
            // Don‘t set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap(); try {//初始化ClassLoader,創建了Catalina實例,賦值給catalinaDaemon bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon
= bootstrap; } else { // When running as a service the call to stop will be on a new // thread so make sure the correct class loader is used to prevent // a range of class not found exceptions. Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } //根據args參數執行不同的命令 try { String command = "start";//默認執行start if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null==daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
View Code 技術分享圖片
public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }
View Code

調用執行start方法前,先判斷catalinaDaemon有沒有被初始化,如果沒有則執行init方法,然後使用Method進行反射調用Catalina的start方法.

知識點補充:

Method是java.lang.reflect包裏的類,可以使用其中的invoke方法來執行所代表的方法,invoke裏有兩個參數,第一個參數是Method方法所在的實體,第二個參數是可變參數,用於Method方法執行時所需要的參數.

Catalina的啟動過程

Catalina的啟動主要調用setAwait,load和start方法來完成.setAwait方法用於設置Server啟動後是否進入等待狀態的標誌,為true進入,否則不進入.load方法用於加載配置文件,start方法用於啟動服務器.

技術分享圖片
public void setAwait(boolean b) {
        await = b;
    }

public void load() { 
        //...創建server
    try {
            getServer().init();
        } catch (LifecycleException e) {
            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                throw new java.lang.Error(e);
            } else {
                log.error("Catalina.start", e);
            }

        }
        //...
    }

    /**
     * Start a new server instance.
     */
    public void start() {

        if (getServer() == null) {
            load();
        }

        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        long t1 = System.nanoTime();

        // Start the new server
        try {
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }
        //...
        if (await) {
            await();
            stop();
        }
    }
View Code

Server的啟動過程

  Server接口中提供了addService(Service service),removeService(Service service)來增加和刪除Service,Server中的init和start方法循環調用Service中的init和start方法來啟動所有Service.Server的默認實現是StandardServer.

Service的啟動過程

  Service的默認實現是StandardService,和StandardServer一樣也繼承自LifecycleMBeanBase類,所以init和start方法最終會調用initInternal和startInternal方法.而StandardService中的initInternal和startInternal方法主要調用container,executors,mapperListener,connectors的init和start方法.

Tomcat聲明周期管理

1.Lifecycle接口

  Tomcat通過Lifecycle接口統一管理生命周期,所有生命周期組件都要實現這個接口,Lifecycle接口主要做了4件事:

1) 定義了13個String類型常量,用於LifecycleEvent事件的type屬性中,作用是為了區分組件發出LifecycleEvent事件的狀態.

2) 定義了3個管理監聽器的方法addLifecycleListener,findLifecycleListener,removeLifecycleListener,分別用來添加,查找,刪除LifecycleListener類型的監聽器.

3) 定義了4個生命周期方法:init,start,stop和destroy,用於執行生命周期的各個階段的操作.

4) 定義了獲取當前狀態的兩個方法:getState和getStateName,用來獲取當前的狀態.

具體接口代碼如下:

技術分享圖片
public interface Lifecycle {
    //13中LifecycleEvent事件的類型
    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";

    //3個管理監聽器的方法
    public void addLifecycleListener(LifecycleListener listener);

    public LifecycleListener[] findLifecycleListeners();

    public void removeLifecycleListener(LifecycleListener listener);

    //4個生命周期方法
    public void init() throws LifecycleException;

    public void start() throws LifecycleException;

    public void stop() throws LifecycleException;

    public void destroy() throws LifecycleException;

    //2個獲取當前狀態的方法
    public LifecycleState getState();

    public String getStateName();
}
View Code

2.LifecycleBase

  LifecycleBase是Lifecycle的默認實現,所有實現了生命周期的組件都直接或間接的繼承了LifecycleBase.LifecycleBase為Lifecycle裏的接口方法提供了默認實現.監聽器管理是專門提供了一個LifecycleSupport類來完成,在LifecycleSupport中定義了LifecycleListener類型的數組,用來保存所有監聽器,並定義了添加,刪除,查找,執行監聽器的方法;生命周期中設置了相應的狀態並調用了相應的模板方法,init,start,stop,destroy所對應的模板方法分別是initInternal,startInternal,stopInternal,destroyInternal方法,執行生命周期就是這4個方法.組件的當前狀態在這4個方法中已經設置好了,所以直接返回就OK了.

Container分析

  Container是Tomcat中容器的接口,通常使用的Servlet就封裝在其子接口Wrapper中.Container一共有4個接口Engine,Host,Context,Wrapper和一個默認實現類ContainerBase,每個子接口都是一個容器,這四個容器都有一個對應的StandardXXX實現類,並且這些實現類都繼承自ContainerBase類.Container還繼承Lifecycle接口,而且ContainerBase間接繼承LifecycleBase. 4個接口Engine,Host,Context,Wrapper也符合Tomcat的生命周期管理模式.

1.Container容器結構

技術分享圖片

2.4個容器的作用

Engine:引擎,用來管理多個站點,一個Service最多只能有一個Engine.

Host:代表一個站點,也可叫虛擬主機,通過配置Host來添加站點.

Context:代表一個應用程序,對應一套程序或者WEB-INF目錄及下面的web.xml

Wraper:每個Wrapper封裝著一個Servlet.

Pipeline-value管道

  Container處理請求是使用Pipeline-value管道來處理的.Pipeline-value是責任鏈模式,區別於普通的責任鏈模式:

1) 每個Pipeline都有特定的Value,而且是在管道的最後執行,這個value叫做BaseValue,是不可刪除的.

2) 在上層容器的BaseValue中會調用下層容器的管道.

Pipeline的實現方法

Pipeline管道的實現分為生命周期管理和處理請求兩部分.

1.生命周期實現方法

Container中的Pipeline在抽象實現類ContainerBase中定義,並在生命周期的startInternal,stopInternal,destroyInternal方法中調用管道的相應生命周期方法.

2.處理請求實現方法

Pipeline調用所包含Value的invoke方法來處理請求,並且在BaseValue裏又調用了子容器Pipeline所包含Value的invoke方法,直到最後調用了Wrapper的Pipeline所包含的BaseValue—StandardWrapperValue

Connector分析

  Connector用於接收請求並將請求封裝成Request和Response來具體處理,最底層是使用Socket來進行連接的,Request和Response是按照Http協議來封裝的,所以Connector同時實現了TCP/IP協議和HTTP協議,Request和Response封裝完之後交給Container進行處理,Container就是Servlet容器,Container處理完成之後返回給Connector,最後Connector使用Socket將處理結果返回給客戶端,整個請求就完成了.

技術分享圖片

  Connector中具體是用ProtocolHandler來處理請求,並且Connector的創建過程主要是初始化ProtocolHandler.不同的ProtocolHandler代表不同的連接類型.Http11Protocol使用的是普通的Socket來連接的.Http11NioProtocol使用的是NioSocket來連接的.

Protocol三個重要組件:

Endpoint:用於處理底層的Socket網絡連接.

Processor:用於將Enpoint接收到的請求封裝成Request

Adapter:用於將封裝好的Request交給Container處理.

最近學習有些懈怠了,主要是工作太忙,下班後基本剩下上床睡覺了.無論如何還是要不斷加強學習,提高自身技術水平.

深入分析理解Tomcat體系結構-讀書筆記