【tomcat系統架構(一)】

四圖帶你瞭解Tomcat系統架構——讓面試官顫抖Tomcat系列

Java高級架構——Tomcat源碼解析之整體流程介紹

 

一、架構

下面談談我對Tomcat架構的理解

 

總體架構:

1、面向組件架構

2、基於JMX

3、事件偵聽

 

1)面向組件架構

 

tomcat代碼看似很龐大,但從結構上看卻很清晰和簡單,它主要由一堆組件組成,如Server、Service、Connector等,並基於JMX管理這些組件,另外實現以上接口的組件也實現了代表生存期的接口Lifecycle,使其組件履行固定的生存期,在其整個生存期的過程中通過事件偵聽LifecycleEvent實現擴展。Tomcat的核心類圖如下所示:



 

Java高級架構——Tomcat源碼解析之整體流程介紹

1、Catalina:與開始/關閉shell腳本交互的主類,因此如果要研究啓動和關閉的過程,就從這個類開始看起。

 

2、Server:是整個Tomcat組件的容器,包含一個或多個Service。

 

3、Service:Service是包含Connector和Container的集合,Service用適當的Connector接收用戶的請求,再發給相應的Container來處理。

 

4、Connector:實現某一協議的連接器,如默認的有實現HTTP、HTTPS、AJP協議的。

 

5、Container:可以理解爲處理某類型請求的容器,處理的方式一般爲把處理請求的處理器包裝爲Valve對象,並按一定順序放入類型爲Pipeline的管道里。Container有多種子類型:Engine、Host、Context和Wrapper,這幾種子類型Container依次包含,處理不同粒度的請求。另外Container裏包含一些基礎服務,如Loader、Manager和Realm。

 

6、Engine:Engine包含Host和Context,接到請求後仍給相應的Host在相應的Context裏處理。

 

7、Host:就是我們所理解的虛擬主機。

 

8、Context:就是我們所部屬的具體Web應用的上下文,每個請求都在是相應的上下文裏處理的

 

9、Wrapper:Wrapper是針對每個Servlet的Container,每個Servlet都有相應的Wrapper來管理。

 

可以看出Server、Service、Connector、Container、Engine、Host、Context和Wrapper這些核心組件的作用範圍是逐層遞減,並逐層包含。

 

 

下面就是些被Container所用的基礎組件:

 

1、Loader:是被Container用來載入各種所需的Class。

2、Manager:是被Container用來管理Session池。

3、Realm:是用來處理安全裏授權與認證。

分析完核心類後,再看看Tomcat啓動的過程,Tomcat啓動的時序圖如下所示:



 

從上圖可以看出,Tomcat啓動分爲init和start兩個過程,核心組件都實現了Lifecycle接口,都需實現start方法,因此在start過程中就是從Server開始逐層調用子組件的start過程。

 

2)基於JMX

JMX(Java Management Extensions,即Java管理擴展)是一個爲應用程序、設備、系統等植入管理功能的框架。

 

Tomcat會爲每個組件進行註冊過程,通過Registry管理起來,而Registry是基於JMX來實現的,因此在看組件的init和start過程實際上就是初始化MBean和觸發MBean的start方法,會大量看到形如:

Registry.getRegistry(null, null).invoke(mbeans, "init", false);

Registry.getRegistry(null, null).invoke(mbeans, "start", false);

 

這樣的代碼,這實際上就是通過JMX管理各種組件的行爲和生命期。

 

3)事件偵聽

 

各個組件在其生命期中會有各種各樣行爲,而這些行爲都有觸發相應的事件,Tomcat就是通過偵聽這些時間達到對這些行爲進行擴展的目的。在看組件的init和start過程中會看到大量如:

 

lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

 

這樣的代碼,這就是對某一類型事件的觸發,如果你想在其中加入自己的行爲,就只用註冊相應類型的事件即可。

 

二、一次完整請求的裏裏外外

前幾天分析了一下Tomcat的架構和啓動過程,今天開始研究它的運轉機制。Tomcat最本質就是個能運行JSP/Servlet的Web服務器 ,因此最典型的應用就是用戶通過瀏覽器訪問服務器,Tomcat接收到請求後轉發給Servlet,由Servlet處理完後,把結果返回給客戶端。今天就專門解析一下這麼一個完整的請求的內部機理。

 

通過DEBUG,一路跟下來,發現Tomcat處理請求的核心過程是以下幾點:

 

1、啓動的時候啓動預支持協議的Endpoint,Endpoint會起專門的線程監聽相應協議的請求,默認的情況下,會啓動JIoEndpoint,JIoEndpoint基於Java ServerSocket接收Http的請求

 

2、ServerSocket接收到客戶端請求的Socket後,一路包裝,並一路從Host一直傳遞到Wrapper,再請求到相應的Servlet

 

下面將重點解析以上兩個過程。

 

 

通過以前的分析(Tomcat源碼分析一)可知道當Tomcat啓動的時候會啓動Connector,此時Connector會通過ProtocolHandler把Endpoint啓動起來。默認情況下,Tomcat會啓動兩種Connector,分別是Http協議和AJP協議的,依次對應Http11Protocol和AjpProtocol,兩者都是啓動JIoEndpoint。下面看看JIoEndpoint的start方法:

public void start()
        throws Exception {
        // Initialize socket if not done before
        if (!initialized) {
            init();
        }
        if (!running) {
            running = true;
            paused = false;

            // Create worker collection
            if (executor == null) {
                workers = new WorkerStack(maxThreads);
            }

            // Start acceptor threads
            for (int i = 0; i < acceptorThreadCount; i++) {
                Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
                acceptorThread.setPriority(threadPriority);
                acceptorThread.setDaemon(daemon);
                acceptorThread.start();
            }
        }
    }

 以上代碼很清晰地表示啓動acceptorThreadCount個線程,每個線程由Acceptor代理,具體看看Acceptor的run方法:

protected class Acceptor implements Runnable {


        /**
         * The background thread that listens for incoming TCP/IP connections and
         * hands them off to an appropriate processor.
         */
        public void run() {

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                // Accept the next incoming connection from the server socket
                try {
                    Socket socket = serverSocketFactory.acceptSocket(serverSocket);
                    serverSocketFactory.initSocket(socket);
                    // Hand this socket off to an appropriate processor
                    if (!processSocket(socket)) {
                        // Close socket right away
                        try {
                            socket.close();
                        } catch (IOException e) {
                            // Ignore
                        }
                    }
                }catch ( IOException x ) {
                    if ( running ) log.error(sm.getString("endpoint.accept.fail"), x);
                } catch (Throwable t) {
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }

                // The processor will recycle itself when it finishes

            }

        }

    }

 由此可得到這麼一個結論:Tomcat就是通過ServerSocket監聽Socket的方式來接收客戶端請求的。找到處理請求的源頭後下面要做的是事情就簡單了,打好斷點,在瀏覽器裏請求一個最簡單的Hello world,一路debug下去。一路跟下來,主流程的時序圖如下所示:



 

從上圖可知,以上過程可分解成以下三個最主要的核心點:

 

1、基於Http1.1協議對Socket的解析和包裝

2、StandardEngineValve、StandardHostValve、StandardContextValve和StandardWrapperValve四種Valve的一路inoke。四種不同層次的Valve做了不同層次的處理和封裝

3、基於責任鏈模式ApplicationFilterChain實現Filter攔截和實際Servlet的請求

 

 

以上三個核心點都是內容非常豐富的可研究點,會在以後幾天逐一進行剖析。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章