tomcat架構分析及配置詳解


瀏覽器訪問服務器的流程

請求發起的過程:

注意:瀏覽器訪問服務器使用的是http協議,http是應用層協議,而具體傳輸還是使用的TCP/IP協議

Tomcat系統總架構

2.1 Tomcat請求處理過程

一個http請求過來,Tomcat會接收,然后根據配置調用不同的servlet來進行處理。

為了解耦,設計了一個Tomcat容器:

因此,Tomcat不僅是一個http服務器,還是一個servlet容器。這也就是它的兩個重要的功能:

  1. 和客戶端瀏覽器交互,進行socket通信,將字節流和Request/Response對象進行轉換
  2. Servlet容器處理邏輯

Tomcat設計了兩個核心組件來完成這兩大功能

  1. 連接器:處理Socket連接
  2. 容器:加載和管理Servlet

Servlet接口和Servlet容器這一整套內容叫做Servlet規范。

2.2 Tomcat Servlet容器處理流程

當用戶請求某個URL資源時

  1. Http服務器會把請求信息使用ServletRuest對象封裝起來
  2. 根據URL和Servlet的映射關系,找到對應的Servlet,進一步去某個具體的Servlet
  3. 如果Servlet還沒有被加載,就用反射機制創建這個Servlet,並調用Servlet的init方法來完成初始化
  4. 接着調用這個具體的Servlet的service方法來處理請求,請求處理結果使用ServletResponse對象封裝
  5. 把ServletResponse對象返回給HTTP服務器,HTTP服務器會把響應結果發送給客戶端

Tomcat連接器組件 Coyote(開椰踢)

3.1 Coyote簡介

Coyote是Tomcat中連接器組件的名稱,是對外的接口。客戶端通過Coyote與服務器建立連接,發送請求並接收響應。

  1. Coyote封裝了底層的網絡通信(Socket請求及響應)
  2. Coyote使容器組件與具體的請求協議及IO操作完全解耦
  3. Coyote 將Socket輸入轉換封裝為Request對象,進一步封裝后交由Servlet的容器處理,請求處理完成后,容器通過Coyote提供的Response對象將結果寫入輸出流
  4. Coyote負責的是具體協議(應用層)和IO(傳輸層)相關內容

Tomcat支持多種應用層協議和IO模型:

名稱 應用層協議或IO模型 描述
應用層 HTTP/1.1 這時大部分Web應用采用的訪問協議
應用層 AJP 用於和WX集成(如Apache),以實現對靜態資源的優化以及集群部署,當前支持AJP/1.3
應用層 HTTP/2 HTTP2大幅度提升了Web性能。下一代HTTP協議,自8.5以及9.0版本之后支持。
傳輸層 NIO 非阻塞I/O,采用Java NIO類庫實現
傳輸層 NIO2 異步IO,采用JDK7 的NIO2類庫實現
傳輸層 APR 采用Apache可移植允許庫實現,是C/C++編寫的本地庫。如果選擇該方案,需要單獨安裝APR庫

Tomcat8.0 以前,Tomcat默認采用的IO方式為BIO,之后改為了NIO。無論是NIO、還是NIO2,性能都是優於以往的BIO,如果采用APR,甚至可以達到Apache HTTP Server的影響性能。

Coyote組件及作用

組件 作用
EndPoint EndPoint 是 Coyote 通信端點,即通信監聽的接⼝,是具體Socket接收和發送處理器,是對傳輸層的抽象,因此EndPoint⽤來實現TCP/IP協議的
Processor Processor 是Coyote 協議處理接⼝ ,如果說EndPoint是⽤來實現TCP/IP協議的,那么Processor⽤來實現HTTP協議,Processor接收來⾃EndPoint的Socket,讀取字節流解析成Tomcat Request和Response對象,並通過Adapter將其提交到容器處理,Processor是對應⽤層協議的抽象
ProtocolHandler Coyote 協議接⼝, 通過Endpoint 和 Processor , 實現針對具體協議的處理能⼒。Tomcat 按照協議和I/O 提供了6個實現類 : AjpNioProtocol ,AjpAprProtocol, AjpNio2Protocol,Http11NioProtocol ,Http11Nio2Protocol ,Http11AprProtocol
Adapter 由於協議不同,客戶端發過來的請求信息也不盡相同,Tomcat定義了⾃⼰的Request類來封裝這些請求信息。ProtocolHandler接⼝負責解析請求並⽣成Tomcat Request類。但是這個Request對象不是標准的ServletRequest,不能⽤Tomcat Request作為參數來調⽤容器。Tomcat設計者的解決⽅案是引⼊CoyoteAdapter,這是適配器模式的經典運⽤,連接器調⽤CoyoteAdapter的Sevice⽅法,傳⼊的是Tomcat Request對象,CoyoteAdapter負責將Tomcat Request轉成ServletRequest,再調⽤容器

Tomcat Servlet容器 Catalina

Catalina是一款Servlet容器,且Catalina是Tomcat的核心。

它的結構如下:

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

每個Service實例下可以有多個Connector實例和一個Container實例

Container組件的具體結構:

  • Engine

表示整個Catalina的Servlet引擎,用來管理多個虛擬站點,一個Service最多只能有一個Engine,但是一個引擎可包含多個Host

  • Host

代表一個虛擬主機,或者說一個站點,可以給Tomcat配置多個虛擬主機地址,而一個虛擬主機下可包含多個Context

  • Context

表示一個Web應用程序,一個Web應用可包含多個Wrapper

  • Wrapper

表示一個Servlet,Wrapper作為容器中的最底層,不能包含子容器

Tomcat服務器核心配置

核心配置:conf/server.xml文件

主要結構如下:
一個Server根元素,有Listener、GlobalNamingResources、Service子標簽

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">
  <Listener />
  
  <GlobalNamingResources></GlobalNamingResources>
 
  <Service name="Catalina"></Service>
 
</Server>

Server標簽詳細:

<!--
port:關閉服務器的監聽端⼝
shutdown:關閉服務器的指令字符串
-->
<Server port="8005" shutdown="SHUTDOWN">
<!-- 以⽇志形式輸出服務器 、操作系統、JVM的版本信息 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<!-- 加載(服務器啟動) 和 銷毀 (服務器停⽌) APR。 如果找不到APR庫, 則會輸出⽇志, 並
不影響 Tomcat啟動 -->
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<!-- 避免JRE內存泄漏問題 -->
<Listener
className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- 加載(服務器啟動) 和 銷毀(服務器停⽌) 全局命名服務 -->
<Listener
className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- 在Context停⽌時重建 Executor 池中的線程, 以避免ThreadLocal 相關的內存泄漏 -->
<Listener
className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
GlobalNamingResources 中定義了全局命名服務
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<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>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
...
</Service>
</Server>

Service標簽

<!--
該標簽⽤於創建 Service 實例,默認使⽤ org.apache.catalina.core.StandardService。
默認情況下,Tomcat 僅指定了Service 的名稱, 值為 "Catalina"。
Service ⼦標簽為 : Listener、Executor、Connector、Engine,
其中:
Listener ⽤於為Service添加⽣命周期監聽器,
Executor ⽤於配置Service 共享線程池,
Connector ⽤於配置Service 包含的鏈接器,
Engine ⽤於配置Service中鏈接器對應的Servlet 容器引擎
-->
<Service name="Catalina">
...
</Service>

Executor標簽

<!--
 默認情況下,Service 並未添加共享線程池配置。 如果我們想添加⼀個線程池, 可以在
<Service> 下添加如下配置:
name:線程池名稱,⽤於 Connector中指定
namePrefix:所創建的每個線程的名稱前綴,⼀個單獨的線程名稱為
namePrefix+threadNumber
maxThreads:池中最⼤線程數
minSpareThreads:活躍線程數,也就是核⼼池線程數,這些線程不會被銷毀,會⼀直存在
maxIdleTime:線程空閑時間,超過該時間后,空閑線程會被銷毀,默認值為6000(1分鍾),單位
毫秒
maxQueueSize:在被執⾏前最⼤線程排隊數⽬,默認為Int的最⼤值,也就是⼴義的⽆限。除⾮特
殊情況,這個值 不需要更改,否則會有請求不會被處理的情況發⽣
prestartminSpareThreads:啟動線程池時是否啟動 minSpareThreads部分線程。默認值為
false,即不啟動
threadPriority:線程池中線程優先級,默認值為5,值從1到10
className:線程池實現類,未指定情況下,默認實現類為
org.apache.catalina.core.StandardThreadExecutor。如果想使⽤⾃定義線程池⾸先需要實現
org.apache.catalina.Executor接⼝
-->
<Executor name="commonThreadPool"
namePrefix="thread-exec-"
maxThreads="200"
minSpareThreads="100"
maxIdleTime="60000"
maxQueueSize="Integer.MAX_VALUE"
prestartminSpareThreads="false"
threadPriority="5"
className="org.apache.catalina.core.StandardThreadExecutor"/>

Connector標簽

默認情況下,server.xml配置了兩個鏈接器,一個支持HTTP協議,一個支持AJP協議。大多數情況下,我們不需要新增鏈接器配置,只需要對已有的鏈接器進行優化

<!--
port:
端⼝號,Connector ⽤於創建服務端Socket 並進⾏監聽, 以等待客戶端請求鏈接。如果該屬性設置
為0, Tomcat將會隨機選擇⼀個可⽤的端⼝號給當前Connector 使⽤
protocol:
當前Connector ⽀持的訪問協議。 默認為 HTTP/1.1 , 並采⽤⾃動切換機制選擇⼀個基於 JAVA
NIO 的鏈接器或者基於本地APR的鏈接器(根據本地是否含有Tomcat的本地庫判定)
connectionTimeOut:
Connector 接收鏈接后的等待超時時間, 單位為 毫秒。 -1 表示不超時。
redirectPort:
當前Connector 不⽀持SSL請求, 接收到了⼀個請求, 並且也符合security-constraint 約束,
需要SSL傳輸,Catalina⾃動將請求重定向到指定的端⼝。
executor:
指定共享線程池的名稱, 也可以通過maxThreads、minSpareThreads 等屬性配置內部線程池。
URIEncoding:
⽤於指定編碼URI的字符編碼, Tomcat8.x版本默認的編碼為 UTF-8 , Tomcat7.x版本默認為ISO-
8859-1
-->
<!--org.apache.coyote.http11.Http11NioProtocol , ⾮阻塞式 Java NIO 鏈接器-->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

可以使用共享線程池

<Connector port="8080"
protocol="HTTP/1.1"
executor="commonThreadPool"
maxThreads="1000"
minSpareThreads="100"
acceptCount="1000"
maxConnections="1000"
connectionTimeout="20000"
compression="on"
compressionMinSize="2048"
disableUploadTimeout="true"
redirectPort="8443"
URIEncoding="UTF-8" />

Engine 標簽

Engine表示Servlet引擎

<!--
name: ⽤於指定Engine 的名稱, 默認為Catalina
defaultHost:默認使⽤的虛擬主機名稱, 當客戶端請求指向的主機⽆效時, 將交由默認的虛擬主機處
理, 默認為localhost
-->
<Engine name="Catalina" defaultHost="localhost">
...
</Engine>

Host標簽

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

可以配置多個host訪問不同的目錄

<Host name="www.aaa.com"  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>
      <Host name="www.bbb.com"  appBase="webapps2"
            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>

Context 標簽

不配做Context的時候,appBase配置的目錄下的所有項目包都會被訪問,如想訪問appBase配置的目錄下的ROOT2,只需要localhost:8080/ROOT2

<Host name="www.abc.com" appBase="webapps" unpackWARs="true"
autoDeploy="true">
<!--
docBase:Web應⽤⽬錄或者War包的部署路徑。可以是絕對路徑,也可以是相對於 Host appBase的
相對路徑。
path:Web應⽤的Context 路徑。如果我們Host名為localhost, 則該web應⽤訪問的根路徑為:
http://localhost:8080/rt。
-->
<Context docBase="D:\apache-tomcat-8.5.32\ROOT" path="rt"/>
<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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM