tomcat原理詳解


tomcat的啟動是通過Bootstrap類的main方法(tomcat6開始也可以直接通過Catlina的main啟動)

 

Bootstrap的啟動

Bootstrap的main方法先new了一個自己的對象(Bootstrap),然后用該對象主要執行了四個方法:

init();

setAwait(true);

load(args);

start();

 

init():初始化了ClassLoader(類加載器,沒它的話后面就沒法加載其他類了),然后用ClassLoader創建了Catlina實例。

 

setAwait(true),load(args),start();這三個方法實際上都是通過反射調用的Catlina實例中所對應的這三個方法。

 

Catlina的啟動

首先Catlina中的setAwait(true)方法:

這個方法設置的值(true或false),是留給后面用的。當通過后面的start()方法啟動完服務器后,會檢查這個值為true還是false,如果為true,調用Catlina的await()方法,tomcat繼續開着。如果為false,則調用Catlina的stop()方法,關閉tomcat。

 

然后是Catlina中的load(args)方法:

Catalina將利用Digest解析server.xml(server的配置文件,server是最頂層容器),並根據server的配置文件創建server實例。

然后調用server實例的init()方法,進行server的初始化。

Server初始化時,又會調用其內部的Service的init方法(server只有一個,但service有多個)。

大體流程如下圖:

 

然后是Catlina中的start()方法:

Catlina的start()方法主要調用了server的start()方法來啟動服務器,然后server的start()方法再調用多個service的start()方法。

大體流程如下圖:

 

Server的啟動

由上面Catlina的啟動我們知道了,

Catlina中的load(args)方法使得Server進行了初始化,

Catlina中的start()方法使得Server也調用了start方法。

 

Server是一個接口,它的默認實現類是StandardServer,所以上面和之后我們操作的Server實際上是操作的StandardServer。

 

StandardServer繼承自LifecycleMBeanBase,而LifecycleMBeanBase又繼承自LifecycelBean。

根據之前的分析我們知道,StandardServer主要要調用兩個方法:init()和start()。

而這兩個方法都不在StandardServer中,實際上都在StandardServer的父類LifecycelBean中。而LifecycelBean中的這兩個方法,實際上由“回頭”調用了StandardServer中的initInternal()和startInternal()方法。

 

也就是StandardServer調用了init()實際上是調用了自己的initInternal()方法。

StandardServer調用了start()實際上是調用了自己的startInternal()方法。

 

initInternal()方法和startInternal()方法“分別循環調用了每一個service的init()方法和start()方法”。

 

除以上方法外,Standard還有addService()方法用來添加service,和remove()方法用來刪除service。

 

另外Standard還擁有await()方法,用法在上面Catlina的啟動中講了。

 

Service的啟動

一個Serve中可以有多個service,Service也是接口,Service接口的默認實現類是StandardService,所以上面和后面討論的service實際上是在操作StandardService。

 

StandardService也繼承於LifecycleMBeanBase,而LifecycleMBeanBase繼承於LifecycelBean,LifecycelBean中存在init()和start()方法。

所以Server循環調用每個StandardService的init()和start()方法,其實是調用的StandardService的父類LifecycelBean中的init()和start()方法,然后init()和start()方法在“回頭調用”StandardService中的initInternal()方法和startInternal()方法

 

也就是說Server循環調用每個StandardService的init()和start()方法,最后執行的是每個Service的initInternal()方法和startInternal()方法。

 

每一個service都是一個對外提供服務的組件,每一個Service中都包含:一個Container+多個Connector,所以service中的方法,都是用來操作這兩種類的。

 

initInternal()方法:

下面是initInternal源碼:

protected void initInternal() throws LifecycleException {
    super.initInternal();
    if(this.container != null) {
        this.container.init();
    }

    Executor[] arr$ = this.findExecutors();
    int arr$1 = arr$.length;

    int len$;
    for(len$ = 0; len$ < arr$1; ++len$) {
        Executor i$ = arr$[len$];
        if(i$ instanceof JmxEnabled) {
            ((JmxEnabled)i$).setDomain(this.getDomain());
        }

        i$.init();
    }

    this.mapperListener.init();
    Object var11 = this.connectorsLock;
    synchronized(this.connectorsLock) {
        Connector[] var12 = this.connectors;
        len$ = var12.length;

        for(int var13 = 0; var13 < len$; ++var13) {
            Connector connector = var12[var13];

            try {
                connector.init();
            } catch (Exception var9) {
                String message = sm.getString("standardService.connector.initFailed", new Object[]{connector});
                log.error(message, var9);
                if(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                    throw new LifecycleException(message);
                }
            }
        }

    }
}

首先,調用Container的init()方法,

再調用mapperListener的init()方法(mapperListener是用來監聽container的變化的),

再調用“多個”excutor的init()方法(excutor是用來在connector中管理線程池的),

再調用Connctor的init()方法。

 

startInternal()方法:

與上同理,也是分別調用四種類的start()方法。

 

總結一下,Server和Service的關系大致如下圖(需要說明的是,下圖中每個類或接口中所包含的方法我並沒有全寫出來,只寫了與流程相關的幾個):

 

Lifecycle接口

將到這里應該提一下Lifecycle接口,該接口的默認實現就是LifecycleBean類。

通過上面提到Server和Service子類我們發現他們都繼承了LifecycleBean類,並調用了該類的init()和start()方法。

實際上凡是擁有“生命周期”的組件都實現了Lifecycle接口,Lifecycle接口的作用就是進行“生命周期的規定”。

該接口主要做了以下四件事:

 

一、定義了13個String常量,這些常量被用於定義“LifecycleEvent事件”的type屬性中 。這樣設計的好處是,只需要發送一種類型事件LifecycleEvent,而根據里面type屬性的值的不同,來判定是什么事件。(否則13種事件就得定義13中事件類)。

 

二、定義了三個管理監聽的方法,分別用來添加、查找、刪除LifecycleListener類型的監聽器。

 

三、定義了四個生命周期方法:init()、start()、stop()、destroy(),用於執行生命周期各個階段的操作。

 

四、定義了用來獲取當前狀態的兩個方法。

 

LifecycleBase實現類

lifecycleBase是Lifecycle接口的默認實現類,所有擁有生命周期的組件都直接或間接的繼承自lifecycleBase類,lifecycleBase為lifecycle接口中的各個方法提供了默認實現。

 

三個管理監聽的方法:

這三個方法分別是addLifecycleListener(添加監聽器)、findLifecycleListeners(查找監聽器)、removeLifecycleListener(刪除監聽器)。

監聽器的管理專門使用了一個“LifecycleSupport類”來完成。

這三個方法都調用了LifecycleSupport中的同名方法。

LifecycleSupport中通過一個數組來保存現有個監聽器。

另外LifecycleSupport中還定義了處理LifecycleEvent時間的方法。

 

四個生命周期方法:

主要就是init()和start()方法,在調用方法之前會先判斷當前狀態與要調用的方法是否匹配,如果不匹配則會執行相應的方法使其匹配(如在低啊用init之前先調用了start,這是就會先執行init)。

之后會調用相應的模板方法(initInternal()和startInternal())讓子類具體執行init和start。

我們先看一下init()方法的源碼:

public final synchronized void init() throws LifecycleException {
    if(!this.state.equals(LifecycleState.NEW)) {
        this.invalidTransition("before_init");
    }

    this.setStateInternal(LifecycleState.INITIALIZING, (Object)null, false);

    try {
        this.initInternal();
    } catch (Throwable var2) {
        ExceptionUtils.handleThrowable(var2);
        this.setStateInternal(LifecycleState.FAILED, (Object)null, false);
        throw new LifecycleException(sm.getString("lifecycleBase.initFail", new Object[]{this.toString()}), var2);
    }

    this.setStateInternal(LifecycleState.INITIALIZED, (Object)null, false);
}

可以看出,init()方法先將當前狀態設置成了INITIALIZING,然后執行的是具體實現類的initInternal()方法。

 

再看看start()的源碼:

public final synchronized void start() throws LifecycleException {
    if(!LifecycleState.STARTING_PREP.equals(this.state) && !LifecycleState.STARTING.equals(this.state) && !LifecycleState.STARTED.equals(this.state)) {
        if(this.state.equals(LifecycleState.NEW)) {
            this.init();
        } else if(this.state.equals(LifecycleState.FAILED)) {
            this.stop();
        } else if(!this.state.equals(LifecycleState.INITIALIZED) && !this.state.equals(LifecycleState.STOPPED)) {
            this.invalidTransition("before_start");
        }

        this.setStateInternal(LifecycleState.STARTING_PREP, (Object)null, false);

        try {
            this.startInternal();
        } catch (Throwable var2) {
            ExceptionUtils.handleThrowable(var2);
            this.setStateInternal(LifecycleState.FAILED, (Object)null, false);
            throw new LifecycleException(sm.getString("lifecycleBase.startFail", new Object[]{this.toString()}), var2);
        }

        if(this.state.equals(LifecycleState.FAILED)) {
            this.stop();
        } else if(!this.state.equals(LifecycleState.STARTING)) {
            this.invalidTransition("after_start");
        } else {
            this.setStateInternal(LifecycleState.STARTED, (Object)null, false);
        }

    } else {
        if(log.isDebugEnabled()) {
            LifecycleException t = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyStarted", new Object[]{this.toString()}), t);
        } else if(log.isInfoEnabled()) {
            log.info(sm.getString("lifecycleBase.alreadyStarted", new Object[]{this.toString()}));
        }

    }
}

由此可看到start方法判斷了當前狀態,如果狀態正確執行的起始是子類的startInternal()方法

 

兩個獲取當前狀態的方法:

在生命周期的相應方法中已經設置了state屬性,這兩個方法就是返回該屬性。

 

Connector

Connector的主要任務是負責處理瀏覽器發送過來的請求,並創建一個Request和Response的對象用於和瀏覽器交換數據,然后產生一個線程用於處理請求,Connector會把Request和Response對象傳遞給該線程,該線程的具體的處理過程是Container容器的事了。Container就是Servlet的容器,Container處理完后會吧結果返回給Connector,最后Connector使用socket將處理結果返回給客戶端,整個請求處理完畢。

Connector的底層是使用socket進行連接,Request和Response時按照http協議(協議可選)來封裝,所以Connector同時實現了TCP/IP和HTTP協議。

很明顯Connector應該可以有多個,因為一次請求對應一個Connector,統一時間可能有多個請求。

 

Connector可以處理不同協議類型的請求,默認處理的是HTTP1.1協議。

Connector中使用ProtocolHandler來具體處理請求,不同的ProtocolHandler代表不同協議的請求類型。

ProtocolHandler中又包含三個重要的組件:

Endpoint,用於處理底層socket網絡連接。

Processor,用於將socket接收到的socket封裝成request。

Adapter,用於將requst交給Container進行處理。

 

具體執行順序如下

一、之前講過了,Catlina會調用load方法,根據server.xml配置文件創建Server對象,之后Server由調用init()創建service,service再調用Connector的init方法創建並初始化。

所以Connector是在Catlina會調用load方法時創建的。

 

二、Conntctor首先執行的是初始化init,Conntctor的初始化主要是用來初始化ProtocolHandler。

所以Conntctor執行init后:

1、先創建一個Adapter,並設置到ProtocolHandler中(這個Adapter后面要用,也就是上面所提到的用於將requst交給Container進行處理。)

2、調用ProtocolHandler的init方法,讓它進行初始化。

3、調用mapperListener的init方法初始化(mapperListener作用是用來監聽容器,容器發生變化會被通知)

 

三、剛剛上面提到了ProtocolHandler的init方法被調用了,我們在看看ProtocolHandler初始化都做了什么。

整個ProtocolHandler結構如下圖:

ProtocolHandler的初始化方法被實現於“AbstractProtocol抽象類”中。

該抽象類有兩種子抽象類:AbstractAjpProtocol和AbstractHttp11Protocol,分別對應了兩種不同的請求協議。

所以最終我們初始化的步驟其實是在AbstractHttp11Protocol抽象類中執行(當協議為HTTP時)。

配置文件server.xml中可以指明需要創建的ProtocolHandler類型,默認是處理HTTP1.1協議的ProtocolHandler,之后我們真正創建的就是AbstractHttp11Protocol抽象類的某一個子類(如Http11NioProtocol)

AbstractHttp11Protocol抽象類的初始化主要是調用了Endpoint的init初始化。

 

四、endpoint的init方法在抽象父類AbstractEndpoint中,是個模板方法,實際上調用的是子類NioEndpoint里面的bind()方法。

這里的bind()方法主要作用是,檢查Acceptor和poller的線程數量是否正確(必須大於等於1)。

 

提一下Acceptor和poller這兩個類,Acceptor的作用是控制與tomcat建立連接的數量,但Acceptor只負責建立連接。socket內容的讀寫是通過Poller來實現的。

 

此時Connector的init初始化就完成了。

 

五、Connector的init方法執行完后,會被調用執行startInternal方法。

同理,此方法會調用protocolHandler.start()方法。

然后protocolHandler的start又會調用endpoint.start()方法。

endpoint的start方法在抽象父類AbstractEndpoint中,是個模板方法,實際上調用的是子類NioEndpoint里面的startInternal()方法。

該方法主要做了:

1、初始化一些屬性

2、根據之前定義的Acceptor和poller的線程數量,來啟動相應數量的Acceptor和poller。

 

其中poller會將請求交給SocketProcessor,而SocketProcessor的職責就是把具體的請求處理過程委派給Handler,handler會執行Processor接口里的process()方法,進行“對request的解析,包括請求頭、請求行和請求體”。

而這個process()方法是在抽象父類AbstractHttp11Processor里實現的,

process()方法會先從socket里讀取http請求數據,並解析請求頭,構造Request對象和Response對象。

 

六、process()方法最后會調用Adapter的service()方法。

Adapter接口只有一個實現類CoyoteAdapter。

service()完成“請求行和請求體的解析”,並把解析出來的信息封裝到Request對象和Response對象中,之后service()便將封裝了Request以及Response對象的Socket傳給Container容器了。

 

傳輸的代碼是:

connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

即:先從Connector中獲取service,然后從service中獲取Container。接着再獲取管道,再獲取管道的第一個值Value,最后調用invoke()方法執行請求。

 

、調用mapperListener的start方法。,該方法注冊了已初始化的組件(在上面講的Connector的init時初始化的mapperListener),然后為這些組件添加監聽器,最后添加容器之間的映射關系。

 

此時Connector的startIntenal就完成了。

 

至此整個Connector啟動完畢,大致的流程圖如下(需要說明的是,下圖中每個類或接口中所包含的方法我並沒有全寫出來,只寫了與流程相關的幾個,並且多處地方的子類選擇不是唯一的,我畫的該流程是基於獲取HTTP1.1協議的請求):

 

Container

Container容器是子容器的父接口,所有的子容器都繼承該接口。

Container容器還繼承Lifecycle接口,這樣就擁有了完整的生命周期,他的子容器也就擁有了完整的生命周期。

Container接口的實現子類為ContainerBase,

其下的四個子容器接口為:Engine、Host、Context、Wrapper。他們之間是逐層包含的,每個service只能有一個Engine,一個Engine能夠含有多個Host,每個Host可以含有多個Context,每個Context能夠含有多個Wrapper。

四個子容器接口也有各自的子實現類,這些實現類繼承自ContainerBase。

 

4中子容器的作用:

1、Engine:接收Connector傳來的request和response,選擇可用的Host來處理當前請求管理Host)。

2、Host:代表一個虛擬主機,也是一個站點。外面以www.demo.com/test這個url為例,www.demo.com這個域名就代表一個Host,該域名對應的就是webapps目錄所代表的站點。

3、Context:代表一個應用,還是以www.demo.com/test這個url為例,通過域名可以直接訪問到ROOT根目錄里面的應用就是主應用。webapps/test目錄可以通過www.demo.com/test訪問到,這個test就又是一個子應用。於是這就是兩個Context(每一個應用對應一個Context)。

所以www.demo.com下的應用都屬於該Host站點。而其他的域名又是其他Host站點。

4、Wrapper:每一個Wrapper封裝一個servlet。

 

這里需要特殊說明的是Container的四個子容器的生命周期:

1、雖然四個子容器的共同父類ContainerBase定義了initInternal()和startInternal()方法,但子容器還是可以根據自身情況再添加內容。

2、ContainerBase的init()方法是service初始化的時候調用的。但四個子容器的init方法“並不是”在ContainerBase的init()方法中被循環調用。而是在執行start()方法時,通過狀態判定來調用的init()(如果沒初始化就初始化)。

3、Context和Wrapper是“動態添加的”,在站點目錄下每放置一個war包,就會動態添加一個Context,在web.xml里每配置一個servlet,就可以動態添加一個Wrapper。所以子容器的start方法不僅僅在“tomcat啟動的時候會被調用”,當"父容器ContainerBase添加某個子容器時",也會調用該子容器的start()方法。

 

Container的執行流程為兩條:

初始化

第一條流程為:Service執行init()調用Container的init()方法(注意,此時Container並不會調用子容器的init()方法),然后Service執行start()時調用Container的start,Container的start再循環調用每一個子容器的start()方法。然后再調用管道的“生命周期管理”(管道不需要初始化,所以在init()中不會調用)。第一條流程的流程圖示如下:

 

Container的init()和start()方法執行內容如下:

一、Container的啟動是通過init()和start()完成的。之前分析過這兩個方法都會通過service來調用。

init()和start存在於LifecycelBean中,實際上最后調用的是ContainerBase中的initInternal()和startInternal()方法。

 

ContainerBase的initInternal方法主要是初始化了ThreadPoolExecutor類(startStopExecutor屬性),用於管理啟動和關閉的線程。

ThreadPoolExecutor繼承自Executor用於管理線程,這里就不過多介紹了。

代碼如下:

    protected void initInternal() throws LifecycleException {
        LinkedBlockingQueue startStopQueue = new LinkedBlockingQueue();
        this.startStopExecutor = new ThreadPoolExecutor(this.getStartStopThreadsInternal(), this.getStartStopThreadsInternal(), 10L, TimeUnit.SECONDS, startStopQueue, new ContainerBase.StartStopThreadFactory(this.getName() + "-startStop-"));
        this.startStopExecutor.allowCoreThreadTimeOut(true);
        super.initInternal();
    }

 

二、ContainerBase執行完initInternal后,會由於service的start的調用,執行ContainerBase的startInternal()方法。

代碼如下:

    protected synchronized void startInternal() throws LifecycleException {
        this.logger = null;
        this.getLogger();

 //如果有Cluster和Realm,則調用他們的start方法。
        Cluster cluster = this.getClusterInternal();
        if(cluster != null && cluster instanceof Lifecycle) {
            ((Lifecycle)cluster).start();
        }

        Realm realm = this.getRealmInternal();
        if(realm != null && realm instanceof Lifecycle) {
            ((Lifecycle)realm).start();
        }

        Container[] children = this.findChildren();
        ArrayList results = new ArrayList();

 //使用startStopExecutor調用新線程來啟動每一個子容器
        for(int fail = 0; fail < children.length; ++fail) {
            results.add(this.startStopExecutor.submit(new ContainerBase.StartChild(children[fail])));
        }

        boolean var10 = false;
        Iterator i$ = results.iterator();

        while(i$.hasNext()) {
            Future result = (Future)i$.next();

            try {
                result.get();
            } catch (Exception var9) {
                log.error(sm.getString("containerBase.threadedStartFailed"), var9);
                var10 = true;
            }
        }

        if(var10) {
            throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"));
        } else {
     //調用管道的啟動方法
            if(this.pipeline instanceof Lifecycle) {
                ((Lifecycle)this.pipeline).start();
            }

     //設置生命周期狀態為STARTING狀態。
            this.setState(LifecycleState.STARTING);

     //調用threadStart方法啟動后台線程
            this.threadStart();
        }
    }

startInternal()方法主要做了5件事:

1、如果有Cluster和Realm,則調用他們的start方法。

Cluster用於配置集群,在server.xml中可配置,它的作用是同步session。

Realm是tomcat的安全域,可以用來管理資源的訪問權限。

 

2、使用startStopExecutor調用新線程來啟動每一個子容器(即調用他們的start()方法),具體啟動過程是通過一個for循環對每個子容器啟動一個線程(這樣可以多個線程同時啟動,效率高),並將返回的Future保存到一個List中,然后遍歷每個Future並調用其get方法。(下面詳細說)

 

3、調用管道中Value的start方法來啟動管道。(下面詳細說)

 

4、設置生命周期狀態為STARTING狀態。

 

5、調用threadStart方法啟動后台線程,該線程是一個while循環,定期調用backgroundProcess方法做一些事情,間隔時間可通過屬性設置,單位是秒,如果小於0就不啟動后台線程了。

backgroundProcess()方法在ContainerBase、StandardContext、StandardWrapper中都有實現。

ContainerBase中的backgroundProcess():調用了Cluster、Realm和管道的backgroundProcess()方法。

StandardContext中的backgroundProcess():調用ContainerBase中的backgroundProcess(),還對Session過期和資源變化進行了處理。

StandardWrapper中的backgroundProcess():調用ContainerBase中的backgroundProcess(),還會對jsp生成的servlet定期進行檢查。

 

至此Container的啟動就完成了,接下來我們詳細的說一下上面的四個子容器的啟動,和管道的啟動。

 

先來看看使用startStopExecutor調用新線程來啟動每一個子容器(即調用他們的start()方法)時,每一個子容器都干了些啥。

由於每一個子容器的接口都繼承自Container接口,而Container接口又繼承自Lifecycle接口,所以每一個子容器都有完整的生命周期(都擁有start和init方法),所以調用各個子容器的start方法實際上就是調用他們各自實現類的startInternal()方法。

 

StandardEngine

protected void initInternal() throws LifecycleException {
    this.getRealm();
    super.initInternal();
}

由源碼可看出init方法調用了getRealm(),作用是如果沒有配置Realm,則使用默認的NullPealm。然后調用了父類ContainerBase中的initInternal方法。

protected synchronized void startInternal() throws LifecycleException {
    if(log.isInfoEnabled()) {
        log.info("Starting Servlet Engine: " + ServerInfo.getServerInfo());
    }

    super.startInternal();
}

由源碼可看出:startInternal()只是調用了父類的startInternal()方法。

 

StandardHost

Host的默認實現類StandardHost沒有重寫initInternal方法,所以初始化時調用的是父類的相應方法。

startInternal代碼如下:

protected synchronized void startInternal() throws LifecycleException {
    String errorValve = this.getErrorReportValveClass();
    if(errorValve != null && !errorValve.equals("")) {
        try {
            boolean t = false;
            Valve[] valves = this.getPipeline().getValves();
            Valve[] valve = valves;
            int len$ = valves.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Valve valve1 = valve[i$];
                if(errorValve.equals(valve1.getClass().getName())) {
                    t = true;
                    break;
                }
            }

            if(!t) {
                Valve var9 = (Valve)Class.forName(errorValve).newInstance();
                this.getPipeline().addValve(var9);
            }
        } catch (Throwable var8) {
            ExceptionUtils.handleThrowable(var8);
            log.error(sm.getString("standardHost.invalidErrorReportValveClass", new Object[]{errorValve}), var8);
        }
    }

    super.startInternal();
}

由此看到此方法就是查看管道中是否有ErrorReportValve,如果沒有就將他添加進去。判斷的方法就是遍歷管道里面的所有value,然后通過每個value的名字進行判斷。

 

StandardContext

在startInternal中通過一個var25的boolean來判斷是否進行下一步的處理,起始位true,當中途遇到問題后改為false,后面某些處理就不做了。

if(var25 && !this.listenerStart()) {
    log.error(sm.getString("standardContext.listenerFail"));
    var25 = false;
}

此處觸發Listener(Listener定義在web.xml中)。

 

if(var25 && !this.filterStart()) {
    log.error(sm.getString("standardContext.filterFail"));
    var25 = false;
}

此處觸發web.xml中配置的filter過濾器。

 

if(var25 && !this.loadOnStartup(this.findChildren())) {
    log.error(sm.getString("standardContext.servletFail"));
    var25 = false;
}

此處初始化了所有Servlet,即調用在web.xml中配置了load-on-startup的servlet的init方法初始化(load-on-startup的作用是標記容器是否在啟動時加載此servlet)。

 

StandardWrapper

StandardWrapper沒有重寫initInternal方法,其startInternal()源碼如下:

protected synchronized void startInternal() throws LifecycleException {
    Notification notification;
    if(this.getObjectName() != null) {
        notification = new Notification("j2ee.state.starting", this.getObjectName(), (long)(this.sequenceNumber++));
        this.broadcaster.sendNotification(notification);
    }

    super.startInternal();
    this.setAvailable(0L);
    if(this.getObjectName() != null) {
        notification = new Notification("j2ee.state.running", this.getObjectName(), (long)(this.sequenceNumber++));
        this.broadcaster.sendNotification(notification);
    }

}

主要就做了三件事:

1、用broadcaster發送通知,只要用於JMX,

2、調用父類的startInternal方法

3、調用setAvailable方法,作用是設置Wrapper包含的所有servlet的有效的起始時間。

 

下面談論管道的startInternal方法:

管道

由源碼可知管道是在ContainerBase中啟動的,而四個子容器都繼承了ContainerBase,所以四個自容器都有屬於自己的管道。

而每一個管道里裝的都是“Value”類型,Value是接口,Value的實現類用於進行各種各樣的具體處理操作。

所謂管道就是指多個處理者(value)對某一個請求“依次”進行處理,請求交給第一個value處理完后,再交給第二個value處理·····,每一條管道的“最后一個Value”都會有點特殊,該Value會將請求發送給下一個管道,然后下一個管道拿到請求后,繼續交給該管道內的第一個value處理·····

舉例,如:

請求到達Engine后,實際上是傳給了Engine的管道(因為Engine繼承了Container,所以他擁有StandardPipeline類型的管道),然后管道中有一個Value first屬性,該屬性是一個鏈式結構,存放在管道中first里面的Value是該管道的第一個value,而該value內部存在指針,指向他的下一個value。

管道就能依靠頭value來遍歷該管道內的每一個value,讓他們依次處理請求。

而Engine管道的最后一個value為StandardEngineValue類,該value會將請求發送給Host的管道。

 

總結一下,每一個子容器都有它的StandardPipeline管道,每一條管道中裝有多個value,value中的 invoke方法用來進行具體的處理請求,每個管道中的最后一個value會將請求傳給下一個子容器的管道。(感覺自己有點啰嗦了。。。 (`・ω・´))

 

回到管道的生命周期講解,

在ContainerBase中調用管道的啟動方法(該語句存在於startInternal中):

if(this.pipeline instanceof Lifecycle) {
    ((Lifecycle)this.pipeline).start();
}

Pipeline的實現類為StandardPipeline類。該類中相應的源碼為:

protected synchronized void startInternal() throws LifecycleException {
    Valve current = this.first;
    if(current == null) {
        current = this.basic;
    }

    for(; current != null; current = current.getNext()) {
        if(current instanceof Lifecycle) {
            ((Lifecycle)current).start();
        }
    }

    this.setState(LifecycleState.STARTING);
}

首先調用了first屬性賦值給了current,first屬性里存儲的是“第一個value”,並將它賦值到了當前value上。

之后做了一個判斷,判斷當前value是否為空,為空就將當前value設置為“最后一個value”。

之后從當前value(即:第一個value)開始調用start方法,每調用完一個,就將當前value的下一個value賦值到當前value上。即:循環調用該管道內所有value的start方法。

 

我們再來看一下value的start方法。

value繼承於生命周期接口,所以調用start就是調用其子類的startInternal()方法。

所有的子value都繼承於ValueBase類,而startInternal方法就是定義在ValueBase類里,源碼如下:

protected synchronized void startInternal() throws LifecycleException {
    this.setState(LifecycleState.STARTING);
}

可以看出ValueBase中的startInternal方法只做了一件事,就是將當前狀態設置為STARTING。

 

至此,第一條流程就完成了。

 

傳值

第二條流程為:Connector的Adapter將request和response傳給Container的管道,從Engine的管道一路處理到Wrapper的管道,Wrapper再將response一路返回給Engine,然后Engine將response返回給Connector,Connector再返回給用戶瀏覽器。

 

需要提前說明的是,四個自容器的管道中,每個管道都有多個value用來依次處理請求,但我在這主要分析“每個子容器管道的最后一個value”,分別是:StandardEngineValue、StandardHostValue、StandardContextValue、StandardWrapperValue。

 

StandardEngineValue

final class StandardEngineValve extends ValveBase {
    private static final StringManager sm = StringManager.getManager("org.apache.catalina.core");

    public StandardEngineValve() {
        super(true);
    }

    public final void invoke(Request request, Response response) throws IOException, ServletException {
        Host host = request.getHost();
        if(host == null) {
            response.sendError(400, sm.getString("standardEngine.noHost", new Object[]{request.getServerName()}));
        } else {
            if(request.isAsyncSupported()) {
                request.setAsyncSupported(host.getPipeline().isAsyncSupported());
            }

            host.getPipeline().getFirst().invoke(request, response);
        }
    }

    public final void event(Request request, Response response, CometEvent event) throws IOException, ServletException {
        request.getHost().getPipeline().getFirst().event(request, response, event);
    }
}

這里的invoke方法主要就做了一件事:

根據請求找到所對應的站點(Host),然后找到host的管道,調用其頭部value的invoke方法,並把request和response傳給他。

 

StandardHostValue

其invoke源碼為:

public final void invoke(Request request, Response response) throws IOException, ServletException {
    Context context = request.getContext();
    if(context == null) {
        response.sendError(500, sm.getString("standardHost.noContext"));
    } else {
        if(request.isAsyncSupported()) {
            request.setAsyncSupported(context.getPipeline().isAsyncSupported());
        }

        boolean asyncAtStart = request.isAsync();
        boolean asyncDispatching = request.isAsyncDispatching();

        try {
            context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
            if(!asyncAtStart && !context.fireRequestInitEvent(request)) {
                return;
            }

            try {
                if(asyncAtStart && !asyncDispatching) {
                    if(!response.isErrorReportRequired()) {
                        throw new IllegalStateException(sm.getString("standardHost.asyncStateError"));
                    }
                } else {
                    context.getPipeline().getFirst().invoke(request, response);
                }
            } catch (Throwable var10) {
                ExceptionUtils.handleThrowable(var10);
                if(response.isErrorReportRequired()) {
                    this.container.getLogger().error("Exception Processing " + request.getRequestURI(), var10);
                } else {
                    request.setAttribute("javax.servlet.error.exception", var10);
                    this.throwable(request, response, var10);
                }
            }

            response.setSuspended(false);
            Throwable t = (Throwable)request.getAttribute("javax.servlet.error.exception");
            if(!context.getState().isAvailable()) {
                return;
            }

            if(response.isErrorReportRequired()) {
                if(t != null) {
                    this.throwable(request, response, t);
                } else {
                    this.status(request, response);
                }
            }

            if(!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) {
                context.fireRequestDestroyEvent(request);
            }
        } finally {
            if(ACCESS_SESSION) {
                request.getSession(false);
            }

            context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
        }

    }
}

Host的用處再上上面已經講過了,一個host代表一個站點(也叫一個虛擬主機),

其處理過程可以總結如下:

1、先根據request請求,選擇一個context容器。如果不為空,則繼續處理。

2、調用Context容器的bind()方法。此方法獲取一條線程,然后讓該線程處理Context。

3、獲取context的管道,再調用管道中頭value的invoke方法,將request和response傳入其中。

 

StandardContextValue

其invoke源碼如下:

public final void invoke(Request request, Response response) throws IOException, ServletException {
    MessageBytes requestPathMB = request.getRequestPathMB();
    if(!requestPathMB.startsWithIgnoreCase("/META-INF/", 0) && !requestPathMB.equalsIgnoreCase("/META-INF") && !requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0) && !requestPathMB.equalsIgnoreCase("/WEB-INF")) {
        Wrapper wrapper = request.getWrapper();
        if(wrapper != null && !wrapper.isUnavailable()) {
            try {
                response.sendAcknowledgement();
            } catch (IOException var6) {
                this.container.getLogger().error(sm.getString("standardContextValve.acknowledgeException"), var6);
                request.setAttribute("javax.servlet.error.exception", var6);
                response.sendError(500);
                return;
            }

            if(request.isAsyncSupported()) {
                request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
            }

            wrapper.getPipeline().getFirst().invoke(request, response);
        } else {
            response.sendError(404);
        }
    } else {
        response.sendError(404);
    }
}

其處理過程可以總結如下:

1、先獲取request的請求路徑,該路徑不能直接訪問WEB-INF或者META-INF目錄下的資源。

2、再根據request,選擇合適的Wrapper。

3、再在response中設置一個sendAcknowledgement(在TCP/IP協議中,如果接收方成功的接收到數據,那么會回復一個ACK數據。)

4、獲取Wrapper的管道,再調用管道中頭value的invoke方法,將request和response傳入其中。

 

StandardWrapperValue

每個Wrapper都封裝着一個servlet,所以Wrapper和servlet有着很深的聯系。

StandardWrapper里會加載他代表的servlet並創建實例(即調用它的init方法),但不會調用servlet的service方法。

StandardWrapperValue會調用sertvlet的service方法。

 

其具體執行順序如下,

1、分配一個Servlet實例,因為StandardWrapper負責加載servlet,所以也是從Wrapper中獲取servlet。

try {
    if(!unavailable) {
        servlet = wrapper.allocate();
    }
} catch (UnavailableException var38) {
    this.container.getLogger().error(sm.getString("standardWrapper.allocateException", new Object[]{wrapper.getName()}), var38);
    long requestPathMB = wrapper.getAvailable();
    if(requestPathMB > 0L && requestPathMB < 9223372036854775807L) {
        response.setDateHeader("Retry-After", requestPathMB);
        response.sendError(503, sm.getString("standardWrapper.isUnavailable", new Object[]{wrapper.getName()}));
    } else if(requestPathMB == 9223372036854775807L) {
        response.sendError(404, sm.getString("standardWrapper.notFound", new Object[]{wrapper.getName()}));
    }
} catch (ServletException var39) {
    this.container.getLogger().error(sm.getString("standardWrapper.allocateException", new Object[]{wrapper.getName()}), StandardWrapper.getRootCause(var39));
    throwable = var39;
    this.exception(request, response, var39);
} catch (Throwable var40) {
    ExceptionUtils.handleThrowable(var40);
    this.container.getLogger().error(sm.getString("standardWrapper.allocateException", new Object[]{wrapper.getName()}), var40);
    throwable = var40;
    this.exception(request, response, var40);
    servlet = null;
}

 

2、執行Servlet相關的所有過濾器:

ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

try {
    if(servlet != null && filterChain != null) {
        if(context.getSwallowOutput()) {
            boolean var29 = false;

            try {
                var29 = true;
                SystemLogHandler.startCapture();
                if(request.isAsyncDispatching()) {
                    ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
                    var29 = false;
                } else if(comet1) {
                    filterChain.doFilterEvent(request.getEvent());
                    var29 = false;
                } else {
                    filterChain.doFilter(request.getRequest(), response.getResponse());
                    var29 = false;
                }
            } finally {
                if(var29) {
                    String time = SystemLogHandler.stopCapture();
                    if(time != null && time.length() > 0) {
                        context.getLogger().info(time);
                    }

                }
            }

            String t2 = SystemLogHandler.stopCapture();
            if(t2 != null && t2.length() > 0) {
                context.getLogger().info(t2);
            }
        } else if(request.isAsyncDispatching()) {
            ((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
        } else if(comet1) {
            filterChain.doFilterEvent(request.getEvent());
        } else {
            filterChain.doFilter(request.getRequest(), response.getResponse());
        }
    }
}

ApplicationFilterChain可以看做是一個“過濾器鏈”,StandardWrapperValve中的invoke會先創建該類的實例,然后調用它的doFilter方法,即從該鏈中的第一個過濾器開始調用。如果執行到了最后一個過濾器,就開始調用Servlet的service方法。

 

3、關閉過濾器鏈

if(filterChain != null) {
    if(request.isComet()) {
        filterChain.reuse();
    } else {
        filterChain.release();
    }
}

 

4、通知Wrapper,重新委派處理完畢的servlet。

try {
    if(servlet != null) {
        wrapper.deallocate(servlet);
    }
} catch (Throwable var31) {
    ExceptionUtils.handleThrowable(var31);
    this.container.getLogger().error(sm.getString("standardWrapper.deallocateException", new Object[]{wrapper.getName()}), var31);
    if(throwable == null) {
        throwable = var31;
        this.exception(request, response, var31);
    }
}

 

至此Container第二條流程也完成了。

 

總結出來,簡易流程圖如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM