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 &quot;%r&quot; %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>

小结

通过本文学习,你应该掌握:

  1. Tomcat整体架构和组件层次关系
  2. 各核心组件的功能和配置方法
  3. 生命周期管理机制
  4. 类加载器的工作原理
  5. 请求处理的Pipeline模式
  6. JNDI资源配置和使用
  7. 管理和监控接口的使用
  8. 开发和生产环境的配置差异

下一篇文章将详细介绍Tomcat Web应用的部署方法。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-08-29 15:40:15

results matching ""

    No results matching ""