Tomcat源碼分析(2)-連接器Connector整體架構

来源:https://www.cnblogs.com/Brake/archive/2020/06/27/13195737.html
-Advertisement-
Play Games

在上一篇博文中,主要分析了tomcat的整體架構,通過上一篇的分析可以知道,tomcat主要有兩部分組成,分別為連接器(Connector)和容器(Container)。本文介紹連接器(Connector)。 一、Connector的主要功能 連接器主要用於對外交流,它負責接收外部的請求,然後把請求 ...


上一篇博文中,主要分析了tomcat的整體架構,通過上一篇的分析可以知道,tomcat主要有兩部分組成,分別為連接器(Connector)和容器(Container)。本文介紹連接器(Connector)。

一、Connector的主要功能

連接器主要用於對外交流,它負責接收外部的請求,然後把請求轉交給container進行處理。主要功能如下:

  1. 監聽網路請求、接受位元組流
  2. 根據應用層協議(HTTP or AJP)把接受到位元組流轉換成TomcatRequest
  3. 把TomcatReqeust轉換成ServletRequest
  4. 調用容器Servlet,得到ServletResponse
  5. 把ServletRespone轉換成TomcatResponse
  6. 把TomcatResponse轉化成位元組流,返回給瀏覽器

基於以上詳細分析可知Connector的主要功能可以抽象為三點

  • 網路監聽
  • 協議解析處理
  • 協議屏蔽轉換(tomcatRequest到servletReqeust轉換,servletResponse到tomcatResponse的轉換)

二、Connetor內部的組件

基於上述的分析,接下來具體看tomcat connector的代碼組件,主要有三個

  • Endpoint-用於網路監聽
  • Processor-用於協議解析處理
  • Adapter-用於轉換,解耦connector和container

tomcat的類設計中增加了一個ProtocolHandler, 把Endpoint和Processor,Adapter封裝到了一起。先看一個整體組件圖。

 三、Endpoint介紹

 Endpoint是通信節點,實現了TCP/IP協議,包含兩個核心組件:

  1. Acceptor,主要用於監聽socket鏈接請求,
  2. SocketProcessor,用於處理接收到的 Socket 請求,實現了runnable介面,在run方法中會調用processor對socket請求進行處理。

Endpoint核心介面

public abstract class AbstractEndpoint<S> {

    protected Acceptor[] acceptors;

    protected abstract SocketProcessorBase<S> createSocketProcessor(
            SocketWrapperBase<S> socketWrapper, SocketEvent event);

    protected SynchronizedStack<SocketProcessorBase<S>> processorCache;
    /**
     * External Executor based thread pool.
     */
    private Executor executor = null;
}

這裡面還有一個Executor, 這個是tomcat自己擴展的線程池。Acceptor監聽到socket請求後,創建SocketProcessor,由Executor來運行SocketProcessor。

Acceptor核心代碼:

    protected class Acceptor extends AbstractEndpoint.Acceptor {
        @Override
        public void run() {
            while (running) {
                state = AcceptorState.RUNNING;
                try {
                    //Accept the next incoming connection from the server
                    SocketChannel socket = serverSock.accept();//監聽請求
                    //setSocketOptions() will hand the socket off to an appropriate processor if successful
                    setSocketOptions(socket);//把請求傳給SocketProcessor
                } catch (Throwable t) {

                }
            }
        }
    }

setSocketOption最終會調用Endpoint的process方法。

Endpoint的process核心方法代碼如下:

    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
                                 SocketEvent event, boolean dispatch) {
        SocketProcessorBase<S> sc = processorCache.pop();
        if (sc == null) {
            sc = createSocketProcessor(socketWrapper, event);//創建SocketProcessor
        } else {
            sc.reset(socketWrapper, event);
        }
        Executor executor = getExecutor();
        executor.execute(sc);//交給線程池進行處理
        return true;
    }

SocketProcessor的抽象類

public abstract class SocketProcessorBase<S> implements Runnable {

    protected SocketWrapperBase<S> socketWrapper;
    protected SocketEvent event;

    @Override
    public final void run() {
        synchronized (socketWrapper) {
            if (socketWrapper.isClosed()) {
                return;
            }
            doRun();
        }
    }

    protected abstract void doRun();
}

SocketProcessor類

  protected class SocketProcessor extends SocketProcessorBase<NioChannel> {

        public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
            super(socketWrapper, event);
        }

        @Override
        protected void doRun() {
            NioChannel socket = socketWrapper.getSocket();
            SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
            getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
        }
    }

上面類中getHandler().process的具體實現。(Handler的介面由Endpoint的內部類進行定義。

    protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> {
        private final Map<S, Processor> connections = new ConcurrentHashMap<>();

        @Override
        public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {

            S socket = wrapper.getSocket();

            Processor processor = connections.get(socket);
            return processor.process(wrapper, status);
        }
    }

至此、請求已經成功傳給可processor。

三、processor、adapter

processor是應用層協議比如HTTP的處理。他負責把請求傳給adapter。核心代碼如下。

    @Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
            throws IOException {

        try {
            getAdapter().service(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

adapter解耦了connector和container的關係,主要負責把tomcatRequest轉換為servletRequest,然後最終調用container,核心代碼如下。

    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
            throws Exception {
        Request request = (Request) req.getNote(ADAPTER_NOTES);
        Response response = (Response) res.getNote(ADAPTER_NOTES);
        if (request == null) {
            // Create objects
            request = connector.createRequest();
            request.setCoyoteRequest(req);
            response = connector.createResponse();
            response.setCoyoteResponse(res);
        }
        // Calling the container
        connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
    }

至此請求到達了container,我們的servlet會對進行業務邏輯處理。

四、細化流程

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • tomcat伺服器源碼解讀,整體結構梳理,開源server,java servlet容器 ...
  • 跟大多數編程語言一樣,python中的迴圈有兩種: while迴圈和for迴圈 首先,介紹一下while迴圈,結合案例做一些練習。 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++while迴圈語法結構:while ...
  • 今天博主再給大家分享一個小項目:MiNi圖書管理系統。用的是Java語言開發的,代碼不多,大概260行左右吧,系統是實現圖書的新增圖書、刪除圖書、借閱圖書、歸還圖書、查看圖書等簡單的功能(後附源代碼)! 首先展示一下運行界面效果圖:運行代碼後,會在控制台顯示如下界面: 然後讓用戶選擇,如果用戶不小心 ...
  • import pandas a=pandas.read_excel() def abc(x): return ','.join(x.values) b=a.groupby(['列名'1])['列名2'].apply(abc) c=b.reset_index() print(c) ...
  • WebSocket 非同步風格伺服器 WebSocket\Server 繼承自 Http\Server,所以 Http\Server 提供的所有 API 和配置項都可以使用。 # ws_server.php class WebSocket { public $server; public functi ...
  • 一.環境要求 安裝java 1.8 以上 命令行運行 java -version 返回版本大於1.8 如果沒有,請安裝java 1.8 二.下載與安裝 下載apktool_x.x.x.jar到本地 官網下載或者 鏡像下載 重命名下載的apktool_x.x.x.jar,改名為apktool.jar ...
  • MongoSpark為入口類,調用MongoSpark.load,該方法返回一個MongoRDD類對象,Mongo Spark Connector框架本質上就是一個大號的自定義RDD,加了些自定義配置、適配幾種分區器規則、Sql的數據封裝等等,個人認為相對核心的也就是分區器的規則實現;弄清楚了其分析 ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 最近一直在關註百度明星吧,發現很多有趣的帖子,於是我就想用python把這些帖子都爬下來,並對內容進行分析。 本文的知識點: 介紹了mysql資料庫內容插入及提取的簡單應用; ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...