自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

【Tomcat源碼分析】從零開(kāi)始理解 HTTP 請(qǐng)求處理

開(kāi)發(fā) 前端
在 Endpoint.start()? 方法中,我們首先會(huì)調(diào)用 bind() 方法,完成 Socket 的綁定,確保 Connector 能夠監(jiān)聽(tīng)來(lái)自網(wǎng)絡(luò)的請(qǐng)求。接著,我們會(huì)創(chuàng)建工作者線程池,為后續(xù)處理請(qǐng)求提供充足的線程資源。隨后,我們會(huì)初始化連接 latch,用于限制請(qǐng)求的并發(fā)量,避免過(guò)多的請(qǐng)求涌入,造成系統(tǒng)崩潰。

前言

終于步入 Connector 的解析階段,這無(wú)疑是 Tomcat 架構(gòu)中最為復(fù)雜的一環(huán)。作為連接器,它的職責(zé)顯而易見(jiàn)——連接。那么,它連接的究竟是什么呢?

Connector 宛如一座橋梁,將來(lái)自客戶端的請(qǐng)求,經(jīng)過(guò)精心封裝成 Request 和 Response 對(duì)象,傳遞給 Container 進(jìn)行處理。Container 完成業(yè)務(wù)邏輯后,Connector 再將處理后的結(jié)果,通過(guò) Response 對(duì)象返回給遠(yuǎn)方的客戶端。

要深入理解 Connector 的精髓,需要我們從四個(gè)關(guān)鍵問(wèn)題出發(fā),逐一探索。

  1. Connector 如何接收來(lái)自遠(yuǎn)方的請(qǐng)求?
  2. 如何將這呼喚化作 Request 和 Response 的身影?
  3. 封裝后的 Request 和 Response 如何被遞交給 Container 處理?
  4. Container 處理完畢后,如何將結(jié)果托付給 Connector,并最終送回客戶端手中?

為了更好地理解 Connector 的內(nèi)部運(yùn)作,讓我們先來(lái)欣賞一幅 Connector 結(jié)構(gòu)圖,它將幫助我們更直觀地感受其內(nèi)部的精妙設(shè)計(jì)。

圖片圖片

【注意】:不同的協(xié)議和通信方式,將催生出不同的 ProtocolHandler 實(shí)現(xiàn)。在 Tomcat 8.5 版本中,ProtocolHandler 的類繼承關(guān)系圖譜如下:

圖片圖片

針對(duì)這幅類繼承層級(jí)圖,我們可以做如下解讀:

ajp 和 http11 代表著兩種截然不同的協(xié)議,而 nio、nio2 和 apr 則分別代表著三種不同的通信方式。值得注意的是,協(xié)議與通信方式并非相互獨(dú)立,它們可以靈活組合,以適應(yīng)不同的場(chǎng)景需求。

ProtocolHandler 內(nèi)部,包含著三個(gè)核心部件:Endpoint、Processor 和 Adapter,它們共同協(xié)作,完成請(qǐng)求的接收、處理和響應(yīng)。

  • Endpoint 負(fù)責(zé)處理底層的 Socket 網(wǎng)絡(luò)連接,它就像是一位網(wǎng)絡(luò)守衛(wèi),負(fù)責(zé)迎接來(lái)自網(wǎng)絡(luò)的呼喚,并將其轉(zhuǎn)化為可供處理的 Socket 連接。Processor 則肩負(fù)著將 Endpoint 接收到的 Socket 封裝成 Request 對(duì)象的重任,它就像一位翻譯官,將網(wǎng)絡(luò)語(yǔ)言轉(zhuǎn)化為服務(wù)器可以理解的語(yǔ)言。Adapter 則充當(dāng)著連接器,它將 Request 對(duì)象傳遞給 Container,以便 Container 進(jìn)行具體的處理。
  • 由于 Endpoint 負(fù)責(zé)處理底層的 Socket 網(wǎng)絡(luò)連接,因此它需要實(shí)現(xiàn) TCP/IP 協(xié)議,而 Processor 則需要實(shí)現(xiàn) HTTP 協(xié)議,以解析 HTTP 請(qǐng)求。Adapter 則將請(qǐng)求適配到 Servlet 容器,使其能夠理解并處理來(lái)自外部的請(qǐng)求。
  • Endpoint 的抽象實(shí)現(xiàn)類 AbstractEndpoint 定義了 Acceptor、AsyncTimeout 兩個(gè)內(nèi)部類和一個(gè) Handler 接口。Acceptor 負(fù)責(zé)監(jiān)聽(tīng)來(lái)自網(wǎng)絡(luò)的請(qǐng)求,一旦有新的請(qǐng)求到來(lái),便會(huì)將其捕獲。AsyncTimeout 則負(fù)責(zé)檢查異步 Request 的超時(shí),確保請(qǐng)求在合理的時(shí)間內(nèi)得到處理。Handler 則負(fù)責(zé)處理接收到的 Socket,它將調(diào)用 Processor 進(jìn)行處理,將 Socket 轉(zhuǎn)換為 Request 對(duì)象,并最終傳遞給 Container。

至此,我們已經(jīng)解開(kāi)了 Connector 如何接收請(qǐng)求、如何將請(qǐng)求封裝成 Request 和 Response,以及封裝后的 Request 和 Response 如何被傳遞給 Container 進(jìn)行處理這三個(gè)關(guān)鍵問(wèn)題。而對(duì)于最后一個(gè)問(wèn)題,即 Container 處理完后如何將結(jié)果返回給客戶端,我們將在深入了解 Container 的運(yùn)作機(jī)制后自然明了,前面章節(jié)已對(duì)此進(jìn)行了詳細(xì)的分析。

Connector 源碼分析入口

在 Service 的標(biāo)準(zhǔn)實(shí)現(xiàn) StandardService 的源碼中,我們發(fā)現(xiàn)其 init()、start()、stop() 和 destroy() 方法分別會(huì)對(duì) Connectors 的同名方法進(jìn)行調(diào)用。值得注意的是,一個(gè) Service 通常會(huì)對(duì)應(yīng)多個(gè) Connector,這意味著 Service 的生命周期管理會(huì)影響到所有與其關(guān)聯(lián)的 Connector。

Service.initInternal()

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();

    if (engine != null) {
        engine.init();
    }

    // Initialize any Executors
    for (Executor executor : findExecutors()) {
        if (executor instanceof JmxEnabled) {
            ((JmxEnabled) executor).setDomain(getDomain());
        }
        executor.init();
    }

    // Initialize mapper listener
    mapperListener.init();

    // Initialize our defined Connectors
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            try {
                connector.init();
            } catch (Exception e) {
                String message = sm.getString(
                        "standardService.connector.initFailed", connector);
                log.error(message, e);

                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                    throw new LifecycleException(message);
            }
        }
    }
}

Service.startInternal()

@Override
protected void startInternal() throws LifecycleException {
    if(log.isInfoEnabled())
        log.info(sm.getString("standardService.start.name", this.name));
    setState(LifecycleState.STARTING);

    // Start our defined Container first
    if (engine != null) {
        synchronized (engine) {
            engine.start();
        }
    }

    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }

    mapperListener.start();

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            try {
                // If it has already failed, don't try and start it
                if (connector.getState() != LifecycleState.FAILED) {
                    connector.start();
                }
            } catch (Exception e) {
                log.error(sm.getString(
                        "standardService.connector.startFailed",
                        connector), e);
            }
        }
    }
}

正如我們所知,Connector 實(shí)現(xiàn)了 Lifecycle 接口,這使得它成為一個(gè)擁有生命周期的組件。因此,Connector 的啟動(dòng)邏輯入口自然而然地落在 init() 和 start() 方法之中。

Connector 構(gòu)造方法

在深入分析 Connector 的啟動(dòng)邏輯之前,不妨先來(lái)觀摩一下 server.xml 文件。這份文件如同 Tomcat 架構(gòu)的藍(lán)圖,清晰地展現(xiàn)了各個(gè)組件之間的聯(lián)系和布局,為我們理解 Connector 的運(yùn)作提供了一個(gè)宏觀的視角。

<?xml versinotallow='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

在 server.xml 文件中,我們發(fā)現(xiàn) Connector 擁有多個(gè)關(guān)鍵屬性,其中 port 和 protocol 尤為重要。默認(rèn)情況下,server.xml 支持兩種協(xié)議:HTTP/1.1 和 AJP/1.3。HTTP/1.1 用于支持傳統(tǒng)的 HTTP 1.1 協(xié)議,而 AJP/1.3 則專門用于支持與 Apache 服務(wù)器的通信,為 Apache 服務(wù)器提供一個(gè)與 Tomcat 交互的橋梁。

現(xiàn)在,讓我們將目光轉(zhuǎn)向 Connector 的構(gòu)造方法:

public Connector() {
    this(null); // 1. 無(wú)參構(gòu)造方法,傳入?yún)?shù)為空協(xié)議,會(huì)默認(rèn)使用`HTTP/1.1`
}

public Connector(String protocol) {
    setProtocol(protocol);
    // Instantiate protocol handler
    // 5. 使用protocolHandler的類名構(gòu)造ProtocolHandler的實(shí)例
    ProtocolHandler p = null;
    try {
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        p = (ProtocolHandler) clazz.getConstructor().newInstance();
    } catch (Exception e) {
        log.error(sm.getString(
                "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    } finally {
        this.protocolHandler = p;
    }

    if (Globals.STRICT_SERVLET_COMPLIANCE) {
        uriCharset = StandardCharsets.ISO_8859_1;
    } else {
        uriCharset = StandardCharsets.UTF_8;
    }
}

@Deprecated
public void setProtocol(String protocol) {
    boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
            AprLifecycleListener.getUseAprConnector();

    // 2. `HTTP/1.1`或`null`,protocolHandler使用`org.apache.coyote.http11.Http11NioProtocol`,不考慮apr
    if ("HTTP/1.1".equals(protocol) || protocol == null) {
        if (aprConnector) {
            setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
        } else {
            setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
        }
    }
    // 3. `AJP/1.3`,protocolHandler使用`org.apache.coyote.ajp.AjpNioProtocol`,不考慮apr
    else if ("AJP/1.3".equals(protocol)) {
        if (aprConnector) {
            setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
        } else {
            setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
        }
    }
    // 4. 其他情況,使用傳入的protocol作為protocolHandler的類名
    else {
        setProtocolHandlerClassName(protocol);
    }
}

在 Connector 的構(gòu)造方法中,我們發(fā)現(xiàn)它主要完成了以下幾項(xiàng)工作:

  • 當(dāng)傳入的參數(shù)為空協(xié)議時(shí),它會(huì)默認(rèn)使用 HTTP/1.1 協(xié)議。
  • 當(dāng)傳入的協(xié)議為 HTTP/1.1 或 null 時(shí),它會(huì)選擇 org.apache.coyote.http11.Http11NioProtocol 作為 ProtocolHandler,并忽略 apr 選項(xiàng)。
  • 當(dāng)傳入的協(xié)議為 AJP/1.3 時(shí),它會(huì)選擇 org.apache.coyote.ajp.AjpNioProtocol 作為 ProtocolHandler,同樣忽略 apr 選項(xiàng)。
  • 對(duì)于其他情況,它會(huì)直接使用傳入的 protocol 作為 ProtocolHandler 的類名。
  • 最后,它會(huì)使用 ProtocolHandler 的類名來(lái)構(gòu)造 ProtocolHandler 的實(shí)例。

Connector.initInternal()

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();

    // Initialize adapter
    // 1. 初始化adapter
    adapter = new CoyoteAdapter(this);
    protocolHandler.setAdapter(adapter);

    // Make sure parseBodyMethodsSet has a default
    // 2. 設(shè)置接受body的method列表,默認(rèn)為POST
    if (null == parseBodyMethodsSet) {
        setParseBodyMethods(getParseBodyMethods());
    }

    if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
        throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoApr",
                getProtocolHandlerClassName()));
    }
    if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
            protocolHandler instanceof AbstractHttp11JsseProtocol) {
        AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                (AbstractHttp11JsseProtocol<?>) protocolHandler;
        if (jsseProtocolHandler.isSSLEnabled() &&
                jsseProtocolHandler.getSslImplementationName() == null) {
            // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
            jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
        }
    }

    // 3. 初始化protocolHandler
    try {
        protocolHandler.init();
    } catch (Exception e) {
        throw new LifecycleException(
                sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
    }
}

Connector 的 init() 方法主要完成了三項(xiàng)重要的初始化工作:

  • 初始化 adapter:Adapter 負(fù)責(zé)將請(qǐng)求傳遞給 Container,因此需要在 init() 方法中完成初始化,以便后續(xù)能夠正常地將請(qǐng)求傳遞給 Container 進(jìn)行處理。
  • 設(shè)置接受 body 的 method 列表:默認(rèn)情況下,Connector 只允許 POST 方法提交 body 數(shù)據(jù),但在某些情況下,可能需要允許其他方法提交 body 數(shù)據(jù),因此需要在 init() 方法中設(shè)置允許提交 body 的方法列表。
  • 初始化 protocolHandler:ProtocolHandler 是 Connector 的核心組件,負(fù)責(zé)處理請(qǐng)求和響應(yīng),因此需要在 init() 方法中完成 protocolHandler 的初始化,以便后續(xù)能夠正常地處理請(qǐng)求和響應(yīng)。

從 ProtocolHandler 的類繼承層級(jí)關(guān)系圖 中,我們可以看到 ProtocolHandler 的子類都必須實(shí)現(xiàn) AbstractProtocol 抽象類。而 protocolHandler.init(); 方法的具體實(shí)現(xiàn)則取決于具體的 ProtocolHandler 子類,它會(huì)根據(jù)不同的協(xié)議和通信方式進(jìn)行相應(yīng)的初始化操作。

代碼正是在這個(gè)抽象類里面。我們來(lái)分析一下。

@Override
public void init() throws Exception {
    if (getLog().isInfoEnabled()) {
        getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
    }

    if (oname == null) {
        // Component not pre-registered so register it
        oname = createObjectName();
        if (oname != null) {
            Registry.getRegistry(null, null).registerComponent(this, oname, null);
        }
    }

    if (this.domain != null) {
        rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
        Registry.getRegistry(null, null).registerComponent(
                getHandler().getGlobal(), rgOname, null);
    }

    // 1. 設(shè)置endpoint的名字,默認(rèn)為:http-nio-{port}
    String endpointName = getName();
    endpoint.setName(endpointName.substring(1, endpointName.length()-1));
    endpoint.setDomain(domain);

    // 2. 初始化endpoint
    endpoint.init();
}

接下來(lái),讓我們一同探究 Endpoint.init() 方法的內(nèi)部。它位于 AbstractEndpoint 抽象類中,采用模板方法模式,巧妙地將核心邏輯委托給子類的 bind() 方法。

public abstract void bind() throws Exception;
public abstract void unbind() throws Exception;
public abstract void startInternal() throws Exception;
public abstract void stopInternal() throws Exception;

public void init() throws Exception {
    // 執(zhí)行bind()方法
    if (bindOnInit) {
        bind();
        bindState = BindState.BOUND_ON_INIT;
    }
    if (this.domain != null) {
        // Register endpoint (as ThreadPool - historical name)
        oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
        Registry.getRegistry(null, null).registerComponent(this, oname, null);

        ObjectName socketPropertiesOname = new ObjectName(domain +
                ":type=ThreadPool,name=\"" + getName() + "\",subType=SocketProperties");
        socketProperties.setObjectName(socketPropertiesOname);
        Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);

        for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
            registerJmx(sslHostConfig);
        }
    }
}

繼續(xù)追尋著代碼的蹤跡,我們終于來(lái)到了 bind() 方法,它揭示了 Connector 初始化的精髓所在。關(guān)鍵的代碼片段 serverSock.socket().bind(addr, getAcceptCount());用于 將 ServerSocket 綁定到指定的 IP 地址和端口

@Override
public void bind() throws Exception {

    if (!getUseInheritedChannel()) {
        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        //綁定ServerSocket到指定的IP和端口
        serverSock.socket().bind(addr,getAcceptCount());
    } else {
        // Retrieve the channel provided by the OS
        Channel ic = System.inheritedChannel();
        if (ic instanceof ServerSocketChannel) {
            serverSock = (ServerSocketChannel) ic;
        }
        if (serverSock == null) {
            throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
        }
    }

    serverSock.configureBlocking(true); //mimic APR behavior

    // Initialize thread count defaults for acceptor, poller
    if (acceptorThreadCount == 0) {
        // FIXME: Doesn't seem to work that well with multiple accept threads
        acceptorThreadCount = 1;
    }
    if (pollerThreadCount <= 0) {
        //minimum one poller thread
        pollerThreadCount = 1;
    }
    setStopLatch(new CountDownLatch(pollerThreadCount));

    // Initialize SSL if needed
    initialiseSsl();

    selectorPool.open();
}

至此,我們已將 Connector 的 init() 方法剖析完畢,接下來(lái),讓我們將目光轉(zhuǎn)向 start() 方法。start() 方法的核心邏輯,僅僅是簡(jiǎn)潔的一行代碼:調(diào)用 ProtocolHandler.start() 方法,將 Connector 的啟動(dòng)大任委托給 ProtocolHandler。

Connector.startInternal()

@Override
protected void startInternal() throws LifecycleException {

    // Validate settings before starting
    if (getPort() < 0) {
        throw new LifecycleException(sm.getString(
                "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
    }

    setState(LifecycleState.STARTING);

    try {
        protocolHandler.start();
    } catch (Exception e) {
        throw new LifecycleException(
                sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
    }
}

現(xiàn)在,讓我們深入 ProtocolHandler.start() 方法,探索啟動(dòng)過(guò)程中的關(guān)鍵步驟。它首先會(huì)調(diào)用 Endpoint.start() 方法,啟動(dòng) Endpoint,以便監(jiān)聽(tīng)來(lái)自網(wǎng)絡(luò)的請(qǐng)求。接著,它會(huì)開(kāi)啟異步超時(shí)線程,負(fù)責(zé)監(jiān)控異步請(qǐng)求的超時(shí)情況。該線程的執(zhí)行單元為 AsyncTimeout。

@Override
public void start() throws Exception {
    if (getLog().isInfoEnabled()) {
        getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
    }

    // 1. 調(diào)用`Endpoint.start()`方法
    endpoint.start();

    // Start async timeout thread
    // 2. 開(kāi)啟異步超時(shí)線程,線程執(zhí)行單元為`Asynctimeout`
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
        priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
}

現(xiàn)在,我們將注意力集中在 Endpoint.start() 方法,它負(fù)責(zé)啟動(dòng) Endpoint,為 Connector 迎接來(lái)自網(wǎng)絡(luò)的請(qǐng)求做好準(zhǔn)備。

public final void start() throws Exception {
    // 1. `bind()`已經(jīng)在`init()`中分析過(guò)了
    if (bindState == BindState.UNBOUND) {
        bind();
        bindState = BindState.BOUND_ON_START;
    }
    startInternal();
}

@Override
public void startInternal() throws Exception {
    if (!running) {
        running = true;
        paused = false;

        processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                socketProperties.getProcessorCache());
        eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
        nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                socketProperties.getBufferPool());

        // Create worker collection
        // 2. 創(chuàng)建工作者線程池
        if ( getExecutor() == null ) {
            createExecutor();
        }

        // 3. 初始化連接latch,用于限制請(qǐng)求的并發(fā)量
        initializeConnectionLatch();

        // Start poller threads
        // 4. 開(kāi)啟poller線程。poller用于對(duì)接受者線程生產(chǎn)的消息(或事件)進(jìn)行處理,poller最終調(diào)用的是Handler的代碼
        pollers = new Poller[getPollerThreadCount()];
        for (int i=0; i<pollers.length; i++) {
            pollers[i] = new Poller();
            Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();
        }
        // 5. 開(kāi)啟acceptor線程
        startAcceptorThreads();
    }
}

protected final void startAcceptorThreads() {
    int count = getAcceptorThreadCount();
    acceptors = new Acceptor[count];

    for (int i = 0; i < count; i++) {
        acceptors[i] = createAcceptor();
        String threadName = getName() + "-Acceptor-" + i;
        acceptors[i].setThreadName(threadName);
        Thread t = new Thread(acceptors[i], threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        t.start();
    }
}

在 Endpoint.start() 方法中,我們首先會(huì)調(diào)用 bind() 方法,完成 Socket 的綁定,確保 Connector 能夠監(jiān)聽(tīng)來(lái)自網(wǎng)絡(luò)的請(qǐng)求。接著,我們會(huì)創(chuàng)建工作者線程池,為后續(xù)處理請(qǐng)求提供充足的線程資源。隨后,我們會(huì)初始化連接 latch,用于限制請(qǐng)求的并發(fā)量,避免過(guò)多的請(qǐng)求涌入,造成系統(tǒng)崩潰。

接下來(lái),我們會(huì)創(chuàng)建一個(gè)輪詢 Poller 線程,負(fù)責(zé)處理來(lái)自 Acceptor 線程的事件,并將處理后的事件傳遞給 Handler。Poller 線程會(huì)調(diào)用 Handler 的代碼進(jìn)行處理,最終完成對(duì)請(qǐng)求的處理。最后,我們會(huì)創(chuàng)建一個(gè) Acceptor 線程,專門負(fù)責(zé)監(jiān)聽(tīng)網(wǎng)絡(luò)請(qǐng)求,并將接收到的請(qǐng)求傳遞給 Poller 線程進(jìn)行處理。

至此,我們已將 Connector 源碼入口的分析告一段落,揭開(kāi)了 Connector 啟動(dòng)過(guò)程的神秘面紗。接下來(lái)我們將繼續(xù)深入探索 Connector 的請(qǐng)求邏輯,深入理解 Connector 如何接收請(qǐng)求,如何將請(qǐng)求封裝成 Request 和 Response 對(duì)象,以及如何將這些對(duì)象傳遞給 Container 進(jìn)行處理。讓我們一起探索 Tomcat 的內(nèi)部世界。


責(zé)任編輯:武曉燕 來(lái)源: 碼上遇見(jiàn)你
相關(guān)推薦

2024-10-05 00:00:06

HTTP請(qǐng)求處理容器

2019-01-18 12:39:45

云計(jì)算PaaS公有云

2018-09-14 17:16:22

云計(jì)算軟件計(jì)算機(jī)網(wǎng)絡(luò)

2024-11-27 16:25:54

JVMJIT編譯機(jī)制

2024-11-18 17:31:27

2015-11-17 16:11:07

Code Review

2018-04-18 07:01:59

Docker容器虛擬機(jī)

2020-07-02 15:32:23

Kubernetes容器架構(gòu)

2024-12-06 17:02:26

2021-10-29 08:07:30

Java timeout Java 基礎(chǔ)

2023-11-14 16:14:49

2010-05-26 17:35:08

配置Xcode SVN

2024-05-15 14:29:45

2023-11-09 23:45:01

Pytorch目標(biāo)檢測(cè)

2024-11-28 10:35:47

2024-04-10 07:48:41

搜索引擎場(chǎng)景

2015-10-15 14:16:24

2011-04-06 15:55:50

開(kāi)發(fā)webOS程序webOS

2024-11-18 16:37:35

JMMJava內(nèi)存模型

2017-02-10 09:30:33

數(shù)據(jù)化運(yùn)營(yíng)流量
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)