
Apache Tomcat軟體是Jakarta Servlet、Jakarta Server Pages、Jakarta Expression Language、Jakarta WebSocket、Jakarta annotation和Jakarta Authentication規範的開源實作。簡單來說也是一個基于Servlet、JSP規範的輕量級Web應用伺服器,在中小型系統和并發通路使用者不是很多的場合下被普遍使用,也是大部分Java技術棧開發和調試Web程式的首選。Tomcat、Jetty、Undertow這幾個都是非常有名實作Servlet規範的應用伺服器,Tomcat本身也是業界上非常優秀的中間件,簡單可可以将Tomcat看成是一個Http伺服器+Servlet容器,Servlet 容器是管理和運作 Servlet 的;相信大家對這隻三腳貓Logo都是非常熟悉了,不管是在學校和還是工作都經常使用它
概述
開啟部落格分享已近三個月,感謝所有花時間精力和小編一路學習和成長的夥伴們,有你們的支援,我們繼續再接再厲
**本人部落格網站 **IT小神 www.itxiaoshen.com
定義
Tomcat官網 http://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簡介
大家都非常了解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客戶。
官方使用者指南
Tomcat10.0官方使用者指南 https://tomcat.apache.org/tomcat-10.0-doc/index.html
簡單安裝
#安裝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
架構源碼剖析
整體架構
Tomcat源碼中大量使用模闆方法和擴充卡的設計模式,封裝很多的元件,元件之間呈現出明顯的層級關系,一層套着一層,這就是經典的套娃式架構設計;個人推薦從tomca配置檔案開始了解其架構這個也是基于套娃式架構設計的優點得來。Tomcat 子產品分層結構及相關子產品的功能說明如下圖:
Tomcat 核心元件架構圖如下所示:
上面有些功能我們可以通過上面的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 "%r" %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 使用者的子產品
我們知道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 的轉化。
連接配接器
連接配接器主要需要完成以下三個核心功能:
- 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連接配接。
- 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 架構。
容器
容器主要用于封裝和管理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。
PipeLine和Valve(管道和閥門)
Engine、Host、Context、Wrapper容器都繼承ContainerBase,而ContainerBase有StandardPipeLine對象,每個容器構造方法setBasic設定預設Valve(StandardEngineValve),PipeLine和Valve元件的init、start。
Connector使用容器Container處理請求時,connector.getService().getContainer().getPipeLine().getFirst().invoke(request,response);
啟動流程
整個 Tomcat 其實就是一個 Catalina 執行個體,Tomcat 啟動的時候會初始化這個執行個體,Catalina 執行個體通過加載server.xml 完成其他執行個體的建立,建立并管理一個 Server,Server 建立并管理多個服務, 每個服務又可以有多個Connector 和一個 Container。
我們知道啟動tomcat是執行startup.sh腳本檔案,這個腳本檔案裡又執行catalina.sh最終是執行org.apache.catalina.startup.Bootstrap類。
是以得知Tomcat從Bootstrap類main方法開始,以鍊的方式逐級調用各子產品的init方法進行初始化, 待各個子產品都初始化後, 又會逐級調用各個子產品的start()方法啟動各個子產品;commonLoader、catalinaLoader、sharedLoader這三個類加載器打破雙親委派。下面是tomcat啟動流程時序圖:
内嵌示例
接下來我們示範内嵌tomcat運作示例,建立maven項目,pom檔案
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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方法
并通路http://127.0.0.1:8080/itxs/first.do,收到結果頁面
源碼編譯
官方下載下傳tomcat源碼,目前最新穩定版本為10.0.12
#由于tomcat源碼依賴jakartaee-migration子產品,而jakartaee-migration未釋出到maven repository,我們需要git clone到本地,再mvn install來部署解決tomcat源碼的編譯問題,https://github.com/apache/tomcat-jakartaee-migration
#解壓檔案,進入到tomcat-jakartaee-migration-main目錄,位址欄上輸入cmd進入指令行視窗并且自動進入目前目錄
#執行maven安裝到本地倉庫
mvn clean install
#加壓apache-tomcat-10.0.12-src.zip的檔案,Tomcat源碼并非maven項目結構,但可以通過pom指定java代碼目錄(無需按照src/main結構來),項目目錄下建立pom.xml檔案,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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
#我們在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);
前面章節我們已提到tomcat main函數的入口在org.apache.catalina.startup.Bootstrap裡,知道main函數
會遇到測試類的報錯如下,可以嘗試運作忽略測試類,或者直接删除maven compile時産生的test檔案夾,我們這裡直接删除test檔案夾
由于目前tomcat啟動找不到配置檔案,是以我們在源碼根目錄下建立source檔案夾,并将conf和webapps這兩個目錄轉移到source檔案夾中
然後在運作設定裡添加如下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
配置好指定的catalina.home和catalina.base以及日志相關jvm參數後,啟動Tomcat,到這裡,我們是可以啟動tomcat程式,但是通路http://localhost:8080/ 會報500錯誤,啟動Tomcat BootStrap時未加載JSP編譯器JasperInitializer
#在org.apache.catalina.startup.ContextConfig#configureStart中
webConfig(); // 這句下面添加如下初始化語句
context.addServletContainerInitializer(new JasperInitializer(), null);
重新啟動Tomcat,檢視http://localhost:8080,出現tomcat的頁面
性能調優
關于性能調優方面可以考慮一下幾個:
- 記憶體:jvm參數,這個是實際生産中用的較多的。
- 并發優化:connector開啟線程池及線程池優化;
- 緩存優化:connector 壓縮和用戶端連接配接逾時;
- IO優化:protocol 選擇BIO NIO NIO2(AIO);
- 元件優化:APR sendfile epoll openssl Tomcat native;
我們本篇隻是簡單了解tomcat架構和搭建tomcat源碼調試環境,後續有時間我們再對tomcat源碼和設計模式做進一步剖析和分享