博客 / 詳情

返回

請求在Tomcat源碼中的流轉(基礎篇)

前言

Tomcat作為Java開發者接觸過最重要的web容器,在啓動和處理請求過程中做了海量的事情,初級開發者很少關心,使用SpringMvc之類上層框架一帶而過,然而這些部分是Java和網絡集大成之作,筆者要帶着大家走一遍一次請求,加深tomcat的認知。最好先調試好Tomcat源碼

Tomcat基礎架構

BootStrap和Catalina

BootStrap

BootStrap就是Tomcat的main函數所在位置,在使用過程中執行腳本catlina.sh或者bat文件即可執行java命令並調用BootStrap的main函數實現tomcat的啓動

 public static void main(String args[]) {
 if (daemon == null) {
                // Don't set daemon until init() has completed
                Bootstrap bootstrap = new Bootstrap();
                try {
                    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);
            }
......
}

Catalina

BootStrap是服務器的入口, 會通過start、stop、stopServer、stopServer等反射調用Catalina的對應方法

public void stopServer() throws Exception {

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

Tomcat的核心配置文件server.xml

先來看一下tomcat的容器結構

image.png
tomcat容器有多層,Server、service、Engine、Host、Context等,圖中有省略
比如一個名稱為mytomcat的web項目,對應到Container部分,Context名稱就是mytomcat
再看一下Tomcat的配置文件server.xml


<Server port="8005" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
    <Listener SSLEngine="on"
        className="org.apache.catalina.core.AprLifecycleListener" />
    <Listener className="org.apache.catalina.core.JasperListener" />
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

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

    <Service name="Catalina">

        <Connector URIEncoding="UTF-8" connectionTimeout="20000"
            port="80" protocol="HTTP/1.1" redirectPort="8443" />
        <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

        <Engine defaultHost="localhost" name="Catalina">

            <Realm className="org.apache.catalina.realm.LockOutRealm">
                <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                    resourceName="UserDatabase" />
            </Realm>

            <Host appBase="webapps" autoDeploy="true" name="localhost"
                unpackWARs="true">

                <Valve className="org.apache.catalina.valves.AccessLogValve"
                    directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log."
                    suffix=".txt" />

            </Host>
        </Engine>
    </Service>

在啓動tomcat的時候,catalina的load方法,會讀取server.xml文件的內容,通過Digester組件把server.xml解析成Server對象,並且把Server變成Catalina的成員變量。

我們看一下catalina的load方法中digester.parse()方法執行後的容器代碼結構

image.png
這樣的話,Tomcat的容器的層級結構就建立起來了。

網絡處理部分

Connector

tomcat可以處理多種協議,統一使用Connector組件來實現,在tomcat中一個Service可以對應多個Connector
image.png

ProtocolHandler

connector中有個很重要的成員變量protocolHandler, 用來實現多種協議的解析,image.png
比如http協議。基於tcp做集羣的AJP協議

Endpoint

AbstractEndpoint是Tcp的處理入口,並且持有Executor;Connector的executor和ProtocolHandler的線程池都是使用這個executor
當有網絡任務到來的時候,tomcat會使用這個線程池來處理socket事件
image.png

Acceptor 和 Poller

Acceptor是封裝新連接的任務,Endpoint使用單獨的線程維護 Poller 是java NIO中Selector的封裝,當新連接到來時喚醒Acceptor線程註冊pollerEvent事件來監聽連接
image.png
Poller的實現是java的Selector
image.png

user avatar dm2box 頭像 an_653b347d1d3da 頭像 cunyu1943 頭像 fulng 頭像 edagarli 頭像 mokeywie 頭像 mo_or 頭像 nian_5aedc008c1353 頭像 biubiubiu_5ea3ee0e6b5fd 頭像 goudantiezhuerzi 頭像 buxiyan 頭像 tengteng_5c7902af4b01e 頭像
15 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.