Tomcat 架构与组件详解
Architecture and Components
概述
了解Tomcat的架构和核心组件是深入配置和优化的基础。本文将详细解析Tomcat的设计架构、核心组件及其相互关系。
1. Tomcat整体架构
1.1 架构层次图
Tomcat Server
├── Service (Catalina)
│ ├── Connector (HTTP/HTTPS/AJP)
│ └── Engine
│ └── Host (Virtual Host)
│ └── Context (Web Application)
│ └── Wrapper (Servlet)
├── GlobalNamingResources
└── Listener (LifecycleListener)
1.2 核心组件关系
<!-- server.xml 结构示例 -->
<Server> <!-- 顶级容器 -->
<Service> <!-- 服务组合 -->
<Connector /> <!-- 连接器 -->
<Engine> <!-- 引擎 -->
<Host> <!-- 虚拟主机 -->
<Context> <!-- Web应用上下文 -->
<Wrapper /> <!-- Servlet包装器 -->
</Context>
</Host>
</Engine>
</Service>
</Server>
2. 核心组件详解
2.1 Server组件
Server是Tomcat的最顶层容器,代表整个Tomcat实例。
<Server port="8005" shutdown="SHUTDOWN">
<!-- Server级别的全局资源 -->
<GlobalNamingResources>
<Resource name="UserDatabase"
auth="Container"
type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<!-- 生命周期监听器 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
</Server>
关键属性:
port: 关闭端口,接收SHUTDOWN命令shutdown: 关闭命令字符串address: 监听地址(可选)
2.2 Service组件
Service组合一个或多个连接器和一个引擎。
<Service name="Catalina">
<!-- 连接器组 -->
<Connector port="8080" protocol="HTTP/1.1"/>
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"/>
<Connector port="8009" protocol="AJP/1.3"/>
<!-- 引擎 -->
<Engine name="Catalina" defaultHost="localhost">
<!-- 引擎内容 -->
</Engine>
</Service>
2.3 Connector连接器
连接器负责接收客户端请求并返回响应。
<!-- HTTP连接器 -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="75"
acceptCount="100"
enableLookups="false"
compression="on"
compressionMinSize="2048"/>
<!-- HTTPS连接器 -->
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
keystoreFile="${catalina.home}/conf/keystore.jks"
keystorePass="changeit"
clientAuth="false"
sslProtocol="TLS"/>
<!-- AJP连接器 -->
<Connector port="8009"
protocol="AJP/1.3"
redirectPort="8443"
secretRequired="false"/>
连接器类型:
- HTTP/1.1: 处理HTTP请求
- HTTPS: 处理加密的HTTP请求
- AJP: Apache JServ协议,用于与Apache Web服务器集成
2.4 Engine引擎
Engine是处理请求的核心组件,管理虚拟主机。
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<!-- 集群配置 -->
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
<!-- 认证域 -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<!-- 虚拟主机 -->
<Host name="localhost" appBase="webapps">
<!-- 主机内容 -->
</Host>
</Engine>
关键属性:
name: 引擎名称defaultHost: 默认虚拟主机jvmRoute: 集群中的节点标识
2.5 Host虚拟主机
Host代表一个虚拟主机,可以部署多个Web应用。
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true"
deployOnStartup="true">
<!-- 别名 -->
<Alias>example.com</Alias>
<Alias>www.example.com</Alias>
<!-- 访问日志 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b"/>
<!-- Web应用上下文 -->
<Context path="/app" docBase="/var/webapps/myapp"/>
</Host>
关键属性:
name: 主机名appBase: 应用基础目录unpackWARs: 是否解压WAR文件autoDeploy: 是否自动部署
2.6 Context上下文
Context代表一个Web应用实例。
<!-- 在server.xml中定义 -->
<Context path="/myapp"
docBase="/var/webapps/myapp"
reloadable="true"
crossContext="false">
<!-- 数据源 -->
<Resource name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="20"
maxIdle="10"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb"
username="user"
password="pass"/>
<!-- 环境变量 -->
<Environment name="env/simpleValue"
value="30"
type="java.lang.Integer"/>
</Context>
也可以在独立文件中定义:
<!-- conf/Catalina/localhost/myapp.xml -->
<Context docBase="/var/webapps/myapp" reloadable="true">
<Parameter name="config.file" value="/etc/myapp/config.properties"/>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
3. 生命周期管理
3.1 组件生命周期
// 生命周期接口
public interface Lifecycle {
void start() throws LifecycleException;
void stop() throws LifecycleException;
void addLifecycleListener(LifecycleListener listener);
LifecycleListener[] findLifecycleListeners();
void removeLifecycleListener(LifecycleListener listener);
}
3.2 生命周期监听器
<!-- server.xml中的监听器配置 -->
<Server>
<!-- 版本信息监听器 -->
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- APR生命周期监听器 -->
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
<!-- 内存泄漏预防监听器 -->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<!-- 全局资源生命周期监听器 -->
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- 线程本地泄漏预防监听器 -->
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
</Server>
3.3 自定义生命周期监听器
// 自定义监听器
public class CustomLifecycleListener implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleEvent event) {
String type = event.getType();
if (Lifecycle.START_EVENT.equals(type)) {
System.out.println("Tomcat is starting...");
// 初始化逻辑
} else if (Lifecycle.STOP_EVENT.equals(type)) {
System.out.println("Tomcat is stopping...");
// 清理逻辑
}
}
}
<!-- 在server.xml中注册自定义监听器 -->
<Listener className="com.example.CustomLifecycleListener" />
4. 类加载机制
4.1 类加载器层次
Bootstrap ClassLoader
└── System ClassLoader
└── Common ClassLoader ($CATALINA_HOME/lib)
├── Server ClassLoader ($CATALINA_HOME/server/lib)
└── Shared ClassLoader ($CATALINA_HOME/shared/lib)
└── WebApp ClassLoader (/WEB-INF/lib, /WEB-INF/classes)
4.2 类加载顺序
// Web应用类加载顺序
1. Bootstrap classes (JVM核心类)
2. System classes (CLASSPATH)
3. /WEB-INF/classes
4. /WEB-INF/lib/*.jar
5. Common classes ($CATALINA_HOME/lib)
6. Shared classes ($CATALINA_HOME/shared/lib)
4.3 类加载配置
# conf/catalina.properties
# Common类加载器路径
common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
# Server类加载器路径
server.loader=
# Shared类加载器路径
shared.loader=
# 不扫描的JAR包
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
bootstrap.jar,commons-daemon.jar,tomcat-juli.jar
5. 请求处理流程
5.1 请求处理架构
Client Request
↓
Connector (接收请求)
↓
Engine (选择Host)
↓
Host (选择Context)
↓
Context (选择Servlet)
↓
Wrapper (执行Servlet)
↓
Servlet Response
↓
Client
5.2 Pipeline管道模式
每个容器都有一个Pipeline,包含多个Valve。
// 管道和阀门示例
public interface Pipeline {
Valve getBasic();
void setBasic(Valve valve);
void addValve(Valve valve);
Valve[] getValves();
void removeValve(Valve valve);
}
public interface Valve {
void invoke(Request request, Response response)
throws IOException, ServletException;
}
5.3 自定义Valve
// 自定义访问控制Valve
public class IPFilterValve extends ValveBase {
private String allowedIPs = "127.0.0.1,192.168.1.*";
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
String clientIP = request.getRemoteAddr();
if (!isAllowed(clientIP)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN,
"Access denied for IP: " + clientIP);
return;
}
// 继续处理请求
getNext().invoke(request, response);
}
private boolean isAllowed(String ip) {
// IP检查逻辑
return true;
}
}
<!-- 在Host中配置自定义Valve -->
<Host name="localhost" appBase="webapps">
<Valve className="com.example.IPFilterValve"
allowedIPs="127.0.0.1,192.168.1.*"/>
</Host>
6. JNDI资源管理
6.1 全局JNDI资源
<Server>
<GlobalNamingResources>
<!-- 数据源 -->
<Resource name="jdbc/GlobalDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/globaldb"
username="root"
password="password"/>
<!-- 邮件会话 -->
<Resource name="mail/Session"
auth="Container"
type="javax.mail.Session"
mail.smtp.host="smtp.example.com"
mail.smtp.port="587"
mail.smtp.auth="true"
mail.smtp.starttls.enable="true"
mail.smtp.user="user@example.com"
password="password"/>
<!-- 环境变量 -->
<Environment name="simpleValue"
value="30"
type="java.lang.Integer"
description="Simple Integer Value"/>
</GlobalNamingResources>
</Server>
6.2 应用级JNDI资源
<!-- Context中的本地资源 -->
<Context>
<!-- 本地数据源 -->
<Resource name="jdbc/LocalDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="20"
maxIdle="10"
driverClassName="org.h2.Driver"
url="jdbc:h2:mem:testdb"
username="sa"
password=""/>
<!-- 资源链接(引用全局资源) -->
<ResourceLink name="jdbc/SharedDB"
global="jdbc/GlobalDB"
type="javax.sql.DataSource"/>
</Context>
6.3 JNDI查找示例
// 在Servlet中使用JNDI资源
public class DatabaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try {
// 获取初始上下文
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// 查找数据源
DataSource ds = (DataSource) envCtx.lookup("jdbc/LocalDB");
// 使用数据源
try (Connection conn = ds.getConnection()) {
// 数据库操作
}
} catch (Exception e) {
throw new ServletException("JNDI lookup failed", e);
}
}
}
7. 管理和监控接口
7.1 JMX管理
<!-- 启用JMX管理 -->
<Server>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Service name="Catalina">
<Engine name="Catalina">
<!-- JMX注册 -->
<Valve className="org.apache.catalina.valves.JmxRemoteLifecycleListener"
rmiRegistryPortPlatform="9999"
rmiServerPortPlatform="9998"/>
</Engine>
</Service>
</Server>
7.2 Manager应用
Manager应用提供Web界面和API来管理应用。
# 通过Manager API部署应用
curl -u admin:password "http://localhost:8080/manager/text/deploy?path=/myapp&war=file:/path/to/myapp.war"
# 启动应用
curl -u admin:password "http://localhost:8080/manager/text/start?path=/myapp"
# 停止应用
curl -u admin:password "http://localhost:8080/manager/text/stop?path=/myapp"
# 获取服务器信息
curl -u admin:password "http://localhost:8080/manager/text/serverinfo"
8. 配置最佳实践
8.1 开发环境配置
<!-- 开发环境server.xml配置要点 -->
<Host name="localhost" appBase="webapps"
autoDeploy="true" deployOnStartup="true">
<!-- 开启热部署 -->
<Context reloadable="true" />
<!-- 详细的错误报告 -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="true"
showServerInfo="true"/>
</Host>
8.2 生产环境配置
<!-- 生产环境server.xml配置要点 -->
<Host name="localhost" appBase="webapps"
autoDeploy="false" deployOnStartup="true">
<!-- 关闭热部署 -->
<Context reloadable="false" />
<!-- 隐藏错误信息 -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false"
showServerInfo="false"/>
<!-- 访问日志 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access_log"
suffix=".txt"
pattern="combined"/>
</Host>
小结
通过本文学习,你应该掌握:
- Tomcat整体架构和组件层次关系
- 各核心组件的功能和配置方法
- 生命周期管理机制
- 类加载器的工作原理
- 请求处理的Pipeline模式
- JNDI资源配置和使用
- 管理和监控接口的使用
- 开发和生产环境的配置差异
下一篇文章将详细介绍Tomcat Web应用的部署方法。