2.1 Tomcat 总体架构 第二章:Tomcat 架构原理 2.1 Tomcat 总体架构 2.1.1 Tomcat 架构概览 Tomcat 的架构设计遵循模块化和组件化的原则,使其具有高度的灵活性和可扩展性。从宏观层面来看,Tomcat 的架构可以被划分为几个核心组件,这些组件协同工作,共同完成处理客户端请求、执行 Servlet 代码、生成响应并返回给客户端的任务。 我们可以用一个 Mermaid 的 图来形象地展示 Tomcat 的总体架构: 图 2.1-1:Tomcat 总体架构图 从上图可以看出,Tomcat 的核心组件可以概括为以下几个层次: Server (服务器):Tomcat 的最顶层组件,代表着整个 Tomcat 实例。
Tomcat 的架构设计遵循模块化和组件化的原则,使其具有高度的灵活性和可扩展性。从宏观层面来看,Tomcat 的架构可以被划分为几个核心组件,这些组件协同工作,共同完成处理客户端请求、执行 Servlet 代码、生成响应并返回给客户端的任务。
我们可以用一个 Mermaid 的 graph TD 图来形象地展示 Tomcat 的总体架构:
图 2.1-1:Tomcat 总体架构图
从上图可以看出,Tomcat 的核心组件可以概括为以下几个层次:
Server (服务器):Tomcat 的最顶层组件,代表着整个 Tomcat 实例。一个 Tomcat 进程可以包含一个或多个 Server 组件。Server 的主要职责是管理 Tomcat 实例的生命周期,包括启动、停止等。它也是其他组件的容器。
Service (服务):Service 组件是 Server 的子组件,一个 Server 可以包含一个或多个 Service。每个 Service 负责对外提供一组特定的服务。一个 Service 内部包含一个 Engine 和一个或多个 Connector。Service 的主要职责是将 Connector 接收到的请求交给 Engine 进行处理,并将 Engine 处理后的响应通过 Connector 返回给客户端。
Connector (连接器):Connector 组件负责接收客户端的请求,并将请求传递给 Tomcat 引擎进行处理。同时,Connector 也负责将引擎处理后的响应返回给客户端。Connector 关注的是如何与客户端进行网络通信,以及使用何种协议进行数据传输。Tomcat 支持多种 Connector,例如 HTTP Connector (用于处理 HTTP 请求) 和 AJP Connector (用于与 Apache 等 Web 服务器集成)。
Engine (引擎):Engine 组件是 Tomcat 的核心组件,负责处理 Service 中的所有请求。一个 Service 只能有一个 Engine。Engine 接收到来自 Connector 的请求后,会根据请求的 URL 和配置,将请求路由到合适的 Host 进行处理。Engine 就像一个请求处理的 “中央处理器”。
Host (虚拟主机):Host 组件代表一个虚拟主机,负责管理一组 Web 应用 (Context)。一个 Engine 可以包含多个 Host。每个 Host 可以配置一个或多个域名,当请求到达 Engine 后,Engine 会根据请求的域名选择合适的 Host 进行处理。Host 的主要职责是将请求路由到特定的 Web 应用 (Context)。
Context (上下文/Web 应用):Context 组件代表一个 Web 应用。它是 Tomcat 中最小的可部署单元。一个 Host 可以包含多个 Context。每个 Context 对应一个 Web 应用的目录,包含 Web 应用的代码、配置文件、静态资源等。Context 负责加载和运行 Web 应用,处理 Servlet 请求,并生成响应。
Servlet (Servlet 组件):虽然图中 Servlet 被放在 Context 下面,但需要明确的是,Servlet 并非 Tomcat 的架构组件,而是 Web 应用的组件。Tomcat (Context) 负责管理 Servlet 的生命周期,并调用 Servlet 的方法来处理请求。Servlet 是实际处理业务逻辑的组件。
接下来,我们将逐个深入讲解 Tomcat 架构中的核心组件,并结合 server.xml 配置文件,展示如何配置这些组件。server.xml 是 Tomcat 的核心配置文件,Tomcat 的架构组件及其配置都在这个文件中定义。
功能描述:
代表整个 Tomcat 实例。
管理 Tomcat 实例的生命周期 (启动、停止)。
是 Service 组件的容器。
监听关闭命令端口,用于优雅地关闭 Tomcat。
server.xml 配置示例:
<Server port="8005" shutdown="SHUTDOWN"> <!-- ... 其他组件配置 ... --> </Server>
配置详解:
port: 指定 Server 监听的关闭命令端口。当接收到来自该端口的 "SHUTDOWN" 命令时,Tomcat 会优雅地停止。默认端口为 8005。
shutdown: 指定关闭命令字符串。默认值为 SHUTDOWN。为了安全,生产环境中建议修改默认值。
代码实践 (Tomcat 启动类 - 简化示例):
虽然我们不直接编写 Server 组件的代码,但可以理解 Tomcat 的启动类 org.apache.catalina.startup.Bootstrap 的部分逻辑 (简化):
public class Bootstrap { public static void main(String[] args) { try { // 1. 创建 Server 实例 (StandardServer 是 Server 接口的默认实现) Server server = new StandardServer(); // 2. 初始化 Server (例如,读取 server.xml 配置) server.init(); // 3. 启动 Server server.start(); // 4. 等待关闭命令 server.await(); } catch (Exception e) { e.printStackTrace(); } } }
这段代码展示了 Tomcat 启动的核心流程:创建 Server 实例、初始化、启动,并等待关闭命令。server.init() 方法会解析 server.xml 配置文件,创建并配置 Service、Connector、Engine、Host、Context 等组件。
功能描述:
代表一组特定的服务。
包含一个 Engine 和一个或多个 Connector。
将 Connector 接收的请求交给 Engine 处理。
将 Engine 处理后的响应通过 Connector 返回。
可以配置多个 Service,例如,一个 Service 处理 HTTP 请求,另一个 Service 处理 HTTPS 请求。
server.xml 配置示例:
<Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost"> <!-- ... Host 配置 ... --> </Engine> </Service>
配置详解:
name: Service 的名称,用于标识 Service 组件。默认值为 Catalina。
<Connector>: Service 包含的连接器配置。一个 Service 可以包含多个 Connector,例如同时监听 HTTP 和 HTTPS 端口。
<Engine>: Service 包含的引擎配置。每个 Service 只能包含一个 Engine。
代码实践 (Service 接口 - 简化示例):
Service 接口定义了 Service 组件的基本行为 (简化):
public interface Service extends Lifecycle { // 获取 Service 名称 String getName(); void setName(String name); // 获取 Engine Engine getContainer(); void setContainer(Engine engine); // 添加 Connector void addConnector(Connector connector); Connector[] findConnectors(); // ... 生命周期管理方法 (init, start, stop, destroy) ... }
StandardService 是 Service 接口的默认实现。Service 的主要职责是管理 Connector 和 Engine 的生命周期,并将它们关联起来。
功能描述:
接收客户端请求。
将请求转换为 Tomcat 内部可以处理的 Request 对象。
将 Tomcat 生成的 Response 对象转换为客户端可以理解的格式。
负责网络通信,处理 TCP 连接、HTTP 协议解析等底层细节。
支持多种协议,例如 HTTP/1.1, HTTP/2, AJP 等。
server.xml 配置示例 (HTTP Connector):
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
配置详解 (HTTP Connector 常用属性):
port: Connector 监听的端口号。HTTP 默认端口为 8080。
protocol: Connector 使用的协议。常用的值有:
HTTP/1.1: HTTP/1.1 协议。
org.apache.coyote.http11.Http11NioProtocol: 使用 NIO 的 HTTP/1.1 协议 (性能较好)。
org.apache.coyote.http11.Http11AprProtocol: 使用 APR (Apache Portable Runtime) 的 HTTP/1.1 协议 (性能更好,需要安装 APR 库)。
AJP/1.3: AJP 协议,用于与 Apache 等 Web 服务器集成。
connectionTimeout: 连接超时时间,单位毫秒。超过这个时间没有完成连接,Connector 会断开连接。
redirectPort: 如果 Connector 接收到的是 HTTP 请求,但需要重定向到 HTTPS,则重定向到这个端口。通常用于配置 HTTPS Connector 的端口。
maxThreads: Connector 处理请求的最大线程数。
acceptCount: 当所有处理线程都被占用时,可以接受的最大连接请求数。超过这个数量的请求将被拒绝。
URIEncoding: URI 编码格式,通常设置为 UTF-8。
代码实践 (Connector 接口 - 简化示例):
Connector 接口定义了 Connector 组件的基本行为 (简化):
public interface Connector extends Lifecycle { // 获取协议 String getProtocol(); void setProtocol(String protocol); // 获取端口 int getPort(); void setPort(int port); // 设置 Service void setService(Service service); Service getService(); // ... 生命周期管理方法 (init, start, stop, destroy) ... }
Http11NioConnector (NIO HTTP Connector) 和 AjpNioConnector (NIO AJP Connector) 等是 Connector 接口的常见实现类。Connector 的核心职责是监听端口,接收连接,解析协议,并将请求交给 Engine 处理。
功能描述:
Tomcat 的核心组件,Servlet 引擎。
接收来自 Connector 的请求。
根据请求的 Host 名称 (域名) 路由请求到合适的 Host 组件。
管理 Host 组件。
一个 Service 只能有一个 Engine。
server.xml 配置示例:
<Engine name="Catalina" defaultHost="localhost"> <!-- ... Host 配置 ... --> </Engine>
配置详解:
name: Engine 的名称,用于标识 Engine 组件。默认值为 Catalina。
defaultHost: 默认 Host 名称。当请求的 Host 名称无法匹配任何 Host 时,请求会被路由到默认 Host。通常设置为 localhost。
jvmRoute: 用于集群环境下的 Session Sticky (会话粘滞) 功能。
代码实践 (Engine 接口 - 简化示例):
Engine 接口定义了 Engine 组件的基本行为 (简化):
public interface Engine extends Container { // Engine 继承自 Container 接口 // 获取默认 Host 名称 String getDefaultHost(); void setDefaultHost(String defaultHost); // 设置 Service void setService(Service service); Service getService(); // ... Container 接口定义的方法 (addChild, findChild, getChildren, 等) ... // ... 生命周期管理方法 (init, start, stop, destroy) ... }
StandardEngine 是 Engine 接口的默认实现。Engine 的核心职责是接收请求,根据 Host 名称路由请求到 Host,并管理 Host 组件。Engine 本身不直接处理请求,而是将请求委托给 Host 和 Context 进行处理。
功能描述:
代表一个虚拟主机。
管理一组 Web 应用 (Context)。
根据请求的 Context Path (Web 应用路径) 路由请求到合适的 Context 组件。
可以配置多个 Host,实现虚拟主机功能,在同一个 Tomcat 实例上部署多个独立的 Web 站点。
server.xml 配置示例:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/sample" docBase="sample" reloadable="true" /> </Host>
配置详解 (Host 常用属性):
name: Host 的域名。例如 localhost 或 www.example.com。
appBase: Web 应用的根目录。Tomcat 会在这个目录下查找 Web 应用。默认值为 webapps。
unpackWARs: 是否自动解压 WAR 包。设置为 true 时,Tomcat 会自动解压 appBase 目录下的 WAR 包到同名目录。
autoDeploy: 是否自动部署 Web 应用。设置为 true 时,Tomcat 会定期扫描 appBase 目录,自动部署新增的 Web 应用或更新已有的 Web 应用。
deployOnStartup: Tomcat 启动时是否部署 Web 应用。
<Context>: Host 包含的 Context 配置。一个 Host 可以包含多个 Context。
代码实践 (Host 接口 - 简化示例):
Host 接口定义了 Host 组件的基本行为 (简化):
public interface Host extends Container { // Host 继承自 Container 接口 // 获取应用根目录 String getAppBase(); void setAppBase(String appBase); // 是否自动部署 boolean getAutoDeploy(); void setAutoDeploy(boolean autoDeploy); // ... Container 接口定义的方法 (addChild, findChild, getChildren, 等) ... // ... 生命周期管理方法 (init, start, stop, destroy) ... }
StandardHost 是 Host 接口的默认实现。Host 的核心职责是管理 Context,根据 Context Path 路由请求到 Context,并提供虚拟主机功能。
功能描述:
代表一个 Web 应用。
加载和运行 Web 应用。
管理 Web 应用的 Servlet、Filter、Listener 等组件。
处理 Servlet 请求,生成响应。
是 Tomcat 中最小的可部署单元。
server.xml 配置示例 (Context - 在 Host 内部配置):
<Host name="localhost" appBase="webapps" ...> <Context path="/sample" docBase="sample" reloadable="true" /> </Host>
配置详解 (Context 常用属性 - 在 server.xml 中配置):
path: Context Path,Web 应用的访问路径。例如 /sample。
docBase: Web 应用的文档根目录。可以是 Web 应用的目录路径,也可以是 WAR 包的路径。例如 sample (表示 webapps/sample 目录)。
reloadable: 是否启用热加载。设置为 true 时,Tomcat 会监控 Web 应用的类和资源文件,当文件发生变化时,Tomcat 会自动重新加载 Web 应用,方便开发调试。生产环境建议设置为 false。
crossContext: 是否允许跨 Context 访问。
代码实践 (Context 接口 - 简化示例):
Context 接口定义了 Context 组件的基本行为 (简化):
public interface Context extends Container { // Context 继承自 Container 接口 // 获取 Context Path String getPath(); void setPath(String path); // 获取文档根目录 String getDocBase(); void setDocBase(String docBase); // 是否可重新加载 boolean getReloadable(); void setReloadable(boolean reloadable); // ... Container 接口定义的方法 (addChild, findChild, getChildren, 等) ... // ... 生命周期管理方法 (init, start, stop, destroy) ... }
StandardContext 是 Context 接口的默认实现。Context 的核心职责是加载 Web 应用,管理 Servlet 组件,处理请求,并生成响应。Context 是 Servlet 容器的核心组件。
了解 Tomcat 的总体架构后,我们还需要理解请求在 Tomcat 内部是如何流转的。一个 HTTP 请求从客户端发送到 Tomcat,最终被 Servlet 处理并返回响应,经历了以下主要步骤:
客户端发送请求:客户端 (例如浏览器) 发送 HTTP 请求到 Tomcat 的监听端口 (例如 8080)。
Connector 接收请求:Connector 组件监听配置的端口,接收客户端的请求,并建立 TCP 连接。
协议解析:Connector 组件解析 HTTP 协议,将请求数据 (例如请求行、请求头、请求体) 封装成 Tomcat 内部的 Request 对象 (org.apache.catalina.connector.Request)。
Request 转发到 Engine:Connector 将 Request 对象转发到关联的 Service 的 Engine 组件。
Engine 路由到 Host:Engine 组件接收到 Request 对象后,根据请求头中的 Host 名称 (域名) 匹配合适的 Host 组件。如果找不到匹配的 Host,则使用默认 Host。
Host 路由到 Context:Host 组件接收到 Request 对象后,根据请求的 URI 中的 Context Path (Web 应用路径) 匹配合适的 Context 组件。
Context 查找 Servlet:Context 组件接收到 Request 对象后,根据请求的 URI 中的 Servlet Path (Servlet 路径) 查找对应的 Servlet。Servlet 的映射关系通常在 Web 应用的 web.xml 文件或 Servlet 注解中配置。
Servlet 处理请求:Context 组件创建 ServletRequest 和 ServletResponse 对象 (org.apache.catalina.connector.Request 和 org.apache.catalina.connector.Response 实现了 Servlet API 中的接口),并将请求交给 Servlet 的 service() 方法处理。Servlet 在 service() 方法中根据请求类型 (GET, POST 等) 调用 doGet() 或 doPost() 等方法,执行业务逻辑。
Servlet 生成响应:Servlet 处理完请求后,将响应数据写入 ServletResponse 对象。
Context 返回 Response:Context 组件将 ServletResponse 对象返回给 Host 组件。
Host 返回 Response:Host 组件将 ServletResponse 对象返回给 Engine 组件。
Engine 返回 Response:Engine 组件将 ServletResponse 对象返回给 Connector 组件。
Connector 返回响应:Connector 组件将 ServletResponse 对象转换为 HTTP 响应格式,并通过 TCP 连接返回给客户端。
客户端接收响应:客户端 (例如浏览器) 接收到 Tomcat 返回的 HTTP 响应,并进行处理和展示。