非尋常方式學習ApacheTomcat架構及10.0.12源碼編譯

概述

開啟部落格分享已近三個月,感謝所有花時間精力和小編一路學習和成長的夥伴們,有你們的支援,我們繼續再接再厲
**本人部落格網站 **IT小神 www.itxiaoshen.com

定義

Tomcat官網 //tomcat.apache.org/

Apache Tomcat軟體是Jakarta Servlet、Jakarta Server Pages、Jakarta Expression Language、Jakarta WebSocket、Jakarta annotation和Jakarta Authentication規範的開源實現。簡單來說也是一個基於Servlet、JSP規範的輕量級Web應用伺服器,在中小型系統和並發訪問用戶不是很多的場合下被普遍使用,也是大部分Java技術棧開發和調試Web程式的首選,目前官方最新版本為10.0.12 Released,而10.1.0-M6 Released還是alpha階段。

Tomcat最初是由Sun的軟體架構師詹姆斯·鄧肯·戴維森開發的,後來他幫助將其變為開源項目,並由Sun貢獻給Apache軟體基金會,成為Apache的定級項目

Tomcat、Jetty、Undertow這幾個都是非常有名實現Servlet規範的應用伺服器,Tomcat本身也是業界上非常優秀的中間件,簡單可可以將Tomcat看成是一個Http伺服器+Servlet容器,Servlet 容器是管理和運行 Servlet 的;相信大家對這隻三腳貓Logo都是非常熟悉了,不管是在學校和還是工作都經常使用它,特別是Java程式設計師最初學習編程都經歷過在Idea或Eclipse中配置Tomcat啟動Web項目,當然還可以通過基於tomcat maven插件或者SpringBoot內嵌web容器(我們在前面《Spring Boot淺聊入門v2.5.3文章》說到Spring Boot內嵌Tomcat容器其實就是New 創建Tomcat的實例)方式調試運行。

Servlet簡介

image-20211028165441784

大家都非常了解Java Web的三大組件Servlet,Filter,Listener,但我們本篇決定不展開聊Servlet規範部分,當前面試官也會讓你談談對於Servlet的理解,我們這裡只是簡單提下後續有時間再針對Servlet相關知道再來深入研究分析,這裡主要為了學習tomcat架構實現而簡單說下Servlet容器工作流程:

  • Web客戶向Servlet容器(比如tomcat)發出Http請求;
  • Servlet容器解析Web客戶的Http請求;
  • Servlet容器創建一個HttpRequest對象,在這個對象中封裝Http請求資訊;
  • Servlet容器創建一個HttpResponse對象;
  • Servlet容器調用HttpServlet的service方法,把HttpRequest和HttpResponse對象作為service方法的參數傳給HttpServlet對象;
    • HttpServlet事實上是servlet的一種子類實例也是最一般的實例。當編寫一個servlet時,必須直接或間接實現servlet介面,最可能實現的方法就是擴展javax.servlet.genericservlet或javax.servlet.http.httpservlet,其中genericservlet類提供了servlet介面的基本實現,httpservlet類擴展了genericservlet並且提供了servlet介面中具體於http的實現。
  • HttpServlet調用HttpRequest的有關方法,獲取HTTP請求資訊;
  • HttpServlet調用HttpResponse的有關方法,生成響應數據;
    • 一般通過HttpServletRequest和HttpServletResponse獲取HTTP請求資訊和返迴響應。事實上servlet理論上可以處理多種形式的請求響應形式 http只是其中之一 所以HttpServletRequest HttpServletResponse分別是ServletRequest和ServletResponse的子類。一般,HttpServlet對應HttpServletRequest和HttpServletResponse。
  • Servlet容器把HttpServlet的響應結果傳給Web客戶。

image-20211027180926881

image-20211028152320087

官方用戶指南

Tomcat10.0官方用戶指南 //tomcat.apache.org/tomcat-10.0-doc/index.html

image-20211028105225712

簡單安裝

image-20211027152915344

#安裝Tomcat需要先保證有安裝JDK環境,建議JDK版本為8以上,JDK17現在都已可用了
#解壓文件
unzip apache-tomcat-10.0.12.zip
#進入目錄
cd apache-tomcat-10.0.12/bin
#啟動tomcat
./startup.sh
#查看默認配置8080埠服務是否啟動
netstat -lntp | grep 8080

image-20211027153548811

架構源碼剖析

整體架構

Tomcat源碼中大量使用模板方法和適配器的設計模式,封裝很多的組件,組件之間呈現出明顯的層級關係,一層套著一層,這就是經典的套娃式架構設計;個人推薦從tomca配置文件開始理解其架構這個也是基於套娃式架構設計的優點得來。Tomcat 模組分層結構及相關模組的功能說明如下圖:

image-20211028160758355

image-20211028160921938

Tomcat 核心組件架構圖如下所示:

image-20211028161048236

上面有些功能我們可以通過上面的1.3章節提供的官方用戶指南查閱到相關資訊,這裡簡單羅列幾條說明

  • Listener 組件
    • 可以在 Tomcat 生命周期中完成某些容器相關的監聽器。
  • JNDI
    • JNDI是 Java 命名與目錄介面,是屬於 J2EE 規範的,Tomcat 對其進行了實現。JNDI 在 J2EE 中的角色就是「交換機」,即 J2EE 組件在運行時間接地查找其他組件、資源或服務的通用機制(你可以簡單理解為給資源取個名字,再根據名字來找資源)。
  • Cluster 組件
    • 提供了集群功能,可以將對應容器需要共享的數據同步到集群中的其他 Tomcat 實例中。
  • Realm 組件
    • 提供了容器級別的用戶-密碼-許可權的數據對象,配合資源認證模組使用。
  • Loader 組件
    • Web 應用載入器,用於載入 Web 應用的資源,它要保證不同 Web 應用之間的資源隔離。
  • Manager 組件
    • Servlet 映射器,它屬於 Context 內部的路由映射器,只負責該 Context 容器的路由導航。

Catalina 是 Tomcat 中的一個重要組件,它負責的是解析 Tomcat 的配置文件(server.xml),以此來創建伺服器 Server 組件並進行管理。下面是Tomcat的conf目錄下大名鼎鼎server.xml核心配置的內容結構,Server-Service-(Connector+Engine),在GlobalNamingResouce 域中可以定義全局資源 tomcat-user.xml,在web.xml文件中也有常見如session-config配置session超時時間默認是30分鐘。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <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">
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    </Connector>
    <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 &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>
  • Server :代表了一個 Tomcat 實例,包含了 Servlet 容器以及其他組件,負責組裝並啟動 Servlet 引擎、Tomcat 連接器。每個Tomcat都只有一個Server,表示整個服務環境。一個Server中可以有多個Service。Server就管理多個Service。tomcat源碼中服務繼承自LifeCycle,tomcat服務組件頂層介面,有唯一實現StandardServer。
  • Service:服務是 Server 內部的組件,一個Server中可以有多個Service,它將若干個 Connector 組件綁定到一個 Container,每一個Service中可以有多個Connector和一個Container(Engine)。
    • Connector主要用來接收請求,解析請求內容,封裝request和response,然後將準備好的數據交給Container處理。
    • Container就是我們常說的容器,裡面可以有多個Host,一個host表示一個虛擬主機,就是一個對應一個WebApps. 最後Container處理完請求之後會將響應內容返回給Connecter,再由Connecter返回給客戶端。
    • Executor 執行器:tomcat執行緒池的配置,提供給Connector。
  • Connecter:負責處理用戶的 servlet 請求,並返回對象給 web 用戶的模組

image-20211028134948217

我們知道tomcat是處理http的請求,意味著tomcat使用的是 HTTP 協議進行數據傳輸,而HTTP 協議是一種應用層協議,其本質就是一種瀏覽器與伺服器之間約定好的通訊格式,因此tomcat作為一個Http伺服器需要包含接受連接、解析請求數據、處理請求和發送響應這幾大塊功能。在這裡我們再分析tomcat最核心的兩個功能:

  • 處理 Socket 連接,負責網路位元組流與 Request 和 Response 對象的轉化。
  • 載入和管理 Servlet,由 Servlet 具體負責處理 Request 請求。

Tomcat 最底層使用的是Socket進行連接的,所以這裡也涉及網路IO模型,通過socket監聽本機埠,接收和處理監聽埠的網路請求,Request和Response是按照Http協議來封裝的,所以Connector同時需要實現TCP/IP協議和Http協議;基於核心功能Tomcat 設計了兩個核心組件連接器(Connector)和容器(Container)來分別實現,連接器複雜對外接收和解析請求,封裝request和response,最後把數據交給Containner,容器負責內部處理。

  • 網路通訊。
  • 應用層協議解析。
  • Tomcat Request/Response 與 ServletRequest/ServletResponse 的轉化。

image-20211028152544170

連接器

連接器主要需要完成以下三個核心功能:

  • socket 通訊,也就是網路通訊。
  • 應用層協議解析,解析處理應用層協議,封裝成一個 Request 對象。
  • 將 Request 轉換為 ServletRequest,將 Response 轉換為 ServletResponse。

Tomcat 通過 EndPoint、Processor 和 Adapter這 3 個組件來實現連接器,這三個組件之間通過抽象介面進行交互。從一個請求的正向流程來看, Endpoint 負責提供請求位元組流給 Processor,Processor 負責提供 Tomcat 定義的 Request 對象給 Adapter,Adapter 負責提供標準的 ServletRequest 對象給 Servlet 容器:

  • Endpoint 和 Processor 可以自由組合,放在一起抽象成了 ProtocolHandler 組件,連接器用 ProtocolHandler 來處理網路連接和應用層協議。Connector中具體用事件處理器來處理請求【ProtocoHandler】;不同的ProtocoHandler代表不同的連接類型【所以一個Service中可以有多個Connector】 例如:Http11Protocol使用普通的Socket來連接的,Http11NioProtocol使用NioSocket連接。

image-20211028155211294

  • EndPoint:對接 I/O 模型,提供位元組流給Processor,監聽通訊埠,是對傳輸層的抽象,處理底層Socket的網路連接,用來實現 TCP/IP 協議的。 是一個介面,對應的抽象類為AbstractEndPoint,有很多實現類,比如NioEndPoint,JIoEndPoint等。在其中有兩個組件,一個 是Acceptor,另外一個是SocketProcessor。 Acceptor用於監聽Socket連接請求,SocketProcessor用於處理接收到的Socket請求。EndPoint 接收到 Socket 連接後,生成一個 SocketProcessor 任務提交到執行緒池去處理,SocketProcessor 的 Run 方法會調用 Processor 組件去解析應用層協議,Processor 通過解析生成 Request 對象後,會調用 Adapter 的 Service 方法。
  • Processor:對接應用層協議,提供Tomcat Request對象給Adapter,Processor是用於實現HTTP協議的,也就是說Processor是針對應用層協議的抽象。 Processor接受來自EndPoint的Socket,然後解析成Tomcat Request和Tomcat Response對象,最後通過Adapter 提交給容器。 對應的抽象類為AbstractProcessor,有很多實現類,比如AjpProcessor、Http11Processor等。
  • Adapter:遵循 Servlet 規範,提供ServletRequest給容器,ProtocolHandler介面負責解析請求並生成 Tomcat Request 類。 需要把這個 Request 對象轉換成 ServletRequest。 Tomcat 引入CoyoteAdapter,這是適配器模式的經典運用,連接器調用 CoyoteAdapter 的 sevice 方法,傳入的是 Tomcat Request 對象,CoyoteAdapter 負責將 Tomcat Request 轉成 ServletRequest,再調用容器的 service 方 法,將請求適配到Servlet容器 Container 架構。

image-20211028135951700

image-20211028143227764

容器

容器主要用於封裝和管理Servlet以及具體處理Request請求。Tomcat 中設計四大Servlet容器組件,分別是Engine、Host、Context、Wrapper—>Servlet,這 4 種容器不是平行關係,而是父子關係。在tomcat源碼org.apache.catalina.core.StandardEngine四個都有其標準實現,每一個容器都有一個 Pipeline 對象。

  • Engine:整個 Catalina 的 Servlet 容器引擎,用來管理多個虛擬站點,一個Service最多只能有一個Engine,但是一個引擎可包含多個 Host。
  • Host:代表的是一個虛擬主機,或者說一個站點,可以給 Tomcat 配置多個虛擬主機地址,而一個虛擬主機下可包含多個 Context。
  • Context:表示一個 Web 應用程式,相當於我們在webapp下的應用,一個 Web 應用通常有多個 Servlet,一個Web應用可包含多個 Wrapper子容器。
  • Wrapper:servlet包裝類,包裝Servlet負責管理整個 Servlet 的生命周期,包括裝載、初始化、資源回收等,每一個Wraper都包裝著Servlet。

image-20211028141625551

PipeLine和Valve(管道和閥門)

image-20211028134427551

Engine、Host、Context、Wrapper容器都繼承ContainerBase,而ContainerBase有StandardPipeLine對象,每個容器構造方法setBasic設置默認Valve(StandardEngineValve),PipeLine和Valve組件的init、start。

Connector使用容器Container處理請求時,connector.getService().getContainer().getPipeLine().getFirst().invoke(request,response);

image-20211028134454024

啟動流程

整個 Tomcat 其實就是一個 Catalina 實例,Tomcat 啟動的時候會初始化這個實例,Catalina 實例通過載入server.xml 完成其他實例的創建,創建並管理一個 Server,Server 創建並管理多個服務, 每個服務又可以有多個Connector 和一個 Container。

我們知道啟動tomcat是執行startup.sh腳本文件,這個腳本文件里又執行catalina.sh最終是執行org.apache.catalina.startup.Bootstrap類。

image-20211028174327984

因此得知Tomcat從Bootstrap類main方法開始,以鏈的方式逐級調用各模組的init方法進行初始化, 待各個模組都初始化後, 又會逐級調用各個模組的start()方法啟動各個模組;commonLoader、catalinaLoader、sharedLoader這三個類載入器打破雙親委派。下面是tomcat啟動流程時序圖:

image-20211028152111593

內嵌示例

接下來我們演示內嵌tomcat運行示例,創建maven項目,pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-extend</artifactId>
        <groupId>com.itxs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>tomcat-test</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>8.5.28</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper</artifactId>
            <version>8.5.28</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.3.9</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

創建一個可以測試Servlet,MyFirstServlet.java

package com.itxs;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyFirstServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws  IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.getWriter().print("hello tomcat servlet,access success!!!");
    }
}

TomcatApplication.java文件

package com.itxs;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import javax.servlet.ServletException;
import java.io.File;

public class TomcatApplication {

    public static int TOMCAT_PORT = 8080;
    public static String TOMCAT_HOSTNAME = "127.0.0.1";
    public static String WEBAPP_PATH = "src/main";

    public static void main(String[] args) throws LifecycleException {
        TomcatApplication.run();
    }

    public static void run() throws LifecycleException {
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(TomcatApplication.TOMCAT_PORT);
        tomcat.setHostname(TomcatApplication.TOMCAT_HOSTNAME);
        tomcat.setBaseDir("."); // tomcat 資訊保存在項目下
        StandardContext myContext = null;
        try {
            myContext = (StandardContext) tomcat.addWebapp("/itxs", System.getProperty("user.dir") + File.separator + TomcatApplication.WEBAPP_PATH);
            myContext.setReloadable(false);
            // 上下文監聽器
            myContext.addLifecycleListener(new AprLifecycleListener());
            // 註冊servlet
            tomcat.addServlet("/itxs", "myFirstServlet",new MyFirstServlet());
            // servlet mapping
            myContext.addServletMappingDecoded("/first.do", "myFirstServlet");
            tomcat.start();
            tomcat.getServer().await();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }
}

運行main方法

image-20211028173246613

並訪問//127.0.0.1:8080/itxs/first.do,收到結果頁面

image-20211028173318712

源碼編譯

官方下載tomcat源碼,目前最新穩定版本為10.0.12

image-20211028224343799

#由於tomcat源碼依賴jakartaee-migration模組,而jakartaee-migration未發布到maven repository,我們需要git clone到本地,再mvn install來部署解決tomcat源碼的編譯問題,//github.com/apache/tomcat-jakartaee-migration
#解壓文件,進入到tomcat-jakartaee-migration-main目錄,地址欄上輸入cmd進入命令行窗口並且自動進入當前目錄

image-20211028230523112

#執行maven安裝到本地倉庫
mvn clean install

image-20211028225627024

#加壓apache-tomcat-10.0.12-src.zip的文件,Tomcat源碼並非maven項目結構,但可以通過pom指定java程式碼目錄(無需按照src/main結構來),項目目錄下創建pom.xml文件,內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="//maven.apache.org/POM/4.0.0"
         xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="//maven.apache.org/POM/4.0.0 //maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.github.sources</groupId>
    <artifactId>source-tomcat</artifactId>
    <version>10.0-SNAPSHOT</version>
    <name>source-tomcat</name>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.easymock</groupId>
            <artifactId>easymock</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.10.1</version>
        </dependency>
        <dependency>
            <groupId>wsdl4j</groupId>
            <artifactId>wsdl4j</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>javax.xml</groupId>
            <artifactId>jaxrpc</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt</groupId>
            <artifactId>org.eclipse.jdt.core</artifactId>
            <version>3.25.0</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jdt.core.compiler</groupId>
            <artifactId>ecj</artifactId>
            <version>4.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>jakartaee-migration</artifactId>
            <version>0.2.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>biz.aQute.bnd</groupId>
            <artifactId>biz.aQute.bndlib</artifactId>
            <version>5.2.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>Tomcat10.0</finalName>
        <sourceDirectory>java</sourceDirectory>
        <testSourceDirectory>test</testSourceDirectory>
        <resources>
            <resource>
                <directory>java</directory>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>test</directory>
            </testResource>
        </testResources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
</project>
#由於源碼apache-tomcat-10.0.12的pom文件里的jakartaee-migration的版本為0.2.1-SNAPSHOT,我們改為上面tomcat-jakartaee-migration-main的項目的版本1.0.1-SNAPSHOT

image-20211028230805800

#我們在JDTCompiler里注釋下面三行源碼, 不能會報沒有 CompilerOptions.VERSION_16
//                settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_16);
//                settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_16);
//                settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_16);

image-20211028231443971

前面章節我們已提到tomcat main函數的入口在org.apache.catalina.startup.Bootstrap里,知道main函數

image-20211028231937648

會遇到測試類的報錯如下,可以嘗試運行忽略測試類,或者直接刪除maven compile時產生的test文件夾,我們這裡直接刪除test文件夾

image-20211028232356203

由於目前tomcat啟動找不到配置文件,因此我們在源碼根目錄下創建source文件夾,並將conf和webapps這兩個目錄轉移到source文件夾中

image-20211028235800553

然後在運行設置里添加如下vm參數

-Dcatalina.home=F:\develop\apache-tomcat-10.0.12-src\source
-Dcatalina.base=F:\develop\apache-tomcat-10.0.12-src\source
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=F:\develop\apache-tomcat-10.0.12-src\source\conf\logging.properties

image-20211029000048038

配置好指定的catalina.home和catalina.base以及日誌相關jvm參數後,啟動Tomcat,到這裡,我們是可以啟動tomcat程式,但是訪問//localhost:8080/ 會報500錯誤,啟動Tomcat BootStrap時未載入JSP編譯器JasperInitializer

image-20211029000502119

#在org.apache.catalina.startup.ContextConfig#configureStart中
webConfig(); // 這句下面添加如下初始化語句
context.addServletContainerInitializer(new JasperInitializer(), null);

image-20211028234008344

image-20211028234240294

重新啟動Tomcat,查看//localhost:8080,出現tomcat的頁面

image-20211028234106713

性能調優

關於性能調優方面可以考慮一下幾個:

  • 記憶體:jvm參數,這個是實際生產中用的較多的。
  • 並發優化:connector開啟執行緒池及執行緒池優化;
  • 快取優化:connector 壓縮和客戶端連接超時;
  • IO優化:protocol 選擇BIO NIO NIO2(AIO);
  • 組件優化:APR sendfile epoll openssl Tomcat native;

我們本篇只是簡單理解tomcat架構和搭建tomcat源碼調試環境,後續有時間我們再對tomcat源碼和設計模式做進一步剖析和分享