当前位置: 首页 > news >正文

Tomcat Engine 原理深度解析

第 1 章:Tomcat Engine 的定义与定位

1.1 什么是 Engine?

在 Tomcat 的核心架构中,Engine 是整个 Servlet 容器的“心脏”,负责接收 Connector 传递过来的请求,并将其路由到合适的 Host → Context → Wrapper,最终交给具体的 Servlet 执行。

可以把它类比成高速公路的交通枢纽

  • Connector 像是高速路的入口收费站,负责接收外部车辆(请求)。

  • Engine 是高速路的主干线,决定车辆应该走哪一条支路。

  • Host 是具体的服务区,相当于一个虚拟主机(domain)。

  • Context 是某个服务区里的商场(web 应用)。

  • Wrapper 就是商场里的具体商铺(Servlet)。


1.2 Engine 的地位

在 Tomcat 的 Catalina 容器分层模型中:

  • Server:Tomcat 的顶层容器,代表整个服务器。

  • Service:一个服务,可以包含多个 Connector 和一个 Engine

  • Engine:核心请求分发容器(每个 Service 仅有一个 Engine)

  • Host:虚拟主机,支持多域名部署。

  • Context:Web 应用容器,一个 Host 下可以有多个 Context。

  • Wrapper:最底层,封装具体的 Servlet。

📌 重点:一个 Service 只能绑定一个 Engine,但 Engine 内部可以管理多个 Host,从而实现多站点、多租户


1.3 配置示例

server.xml 中,我们能直观地看到 Engine 的定义:

<Service name="Catalina"><!-- Connector 定义省略 --><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"><Context path="" docBase="ROOT" reloadable="true" /></Host></Engine>
</Service>

解析:

  • Engine 绑定到 Service(如 Catalina Service)。

  • defaultHost="localhost" 指定默认虚拟主机。

  • Host 定义了一个虚拟主机,可绑定多个 Web 应用(Context)。


1.4 源码定位

在 Tomcat 10.x 源码中:

  • org.apache.catalina.Engine 是一个接口,继承自 Container

  • 默认实现类为 org.apache.catalina.core.StandardEngine

    public interface Engine extends Container {// 获取默认Hostpublic String getDefaultHost();// 设置默认Hostpublic void setDefaultHost(String defaultHost);
    }
    

StandardEngine 则实现了核心逻辑:

public class StandardEngine extends ContainerBase implements Engine {private String defaultHost = null;@Overridepublic String getDefaultHost() {return (this.defaultHost);}@Overridepublic void setDefaultHost(String host) {this.defaultHost = host;}
}

可以看到:

  • Engine 其实就是一个 特殊的 Container,它的子容器是 Host

  • 它的关键属性就是 defaultHost


1.5 实际应用场景

假设你要在同一台 Tomcat 部署多个站点:

<Engine name="Catalina" defaultHost="www.example.com"><Host name="www.example.com" appBase="site1" /><Host name="blog.example.com" appBase="site2" />
</Engine>

这样,访问:

  • http://www.example.com/ → 进入 site1

  • http://blog.example.com/ → 进入 site2

👉 Engine 在这里就扮演了 多租户隔离管理者 的角色。


✅ 小结:

  • Engine 是 Service 内的核心容器,负责将请求分发到正确的 Host/Context/Wrapper。

  • 它是 Servlet 容器分层结构的中枢,既是容器(可以包含 Host),又是路由器(决定请求走向)。

  • 配置层面上,Engine 通常只需要指定 defaultHost,但在多站点、多域名部署时会非常关键。

第 2 章:Engine 在 Tomcat 分层架构中的作用

2.1 Tomcat 的容器分层模型

Tomcat 的核心是 Catalina 容器,它采用了分层容器架构(Container Hierarchy),从上到下依次是:

  1. Server(顶层,代表整个 Tomcat 实例)

  2. Service(一个服务,包含一个 Engine 和多个 Connector)

  3. Engine(请求分发枢纽,一个 Service 只能有一个 Engine)

  4. Host(虚拟主机,代表一个域名站点)

  5. Context(Web 应用,一个 Host 下可以有多个 Context)

  6. Wrapper(最底层,封装具体的 Servlet)

👉 这种分层设计,使 Tomcat 容器既清晰又灵活,方便扩展。


2.2 Engine 与其他组件的关系

  • 与 Server 的关系

    • Server 是最顶层,包含多个 Service

    • 每个 Service 必须有一个 Engine,因此 Engine 相当于 Server 与 Connector 的桥梁。

  • 与 Service 的关系

    • Service 管理一组 Connector(负责协议/网络)和一个 Engine(负责容器)。

    • 请求流向:Connector → Engine

  • 与 Host 的关系

    • Engine 的直接子容器就是 Host。

    • 一个 Engine 可以有多个 Host,用来支持多域名。

    • Host 内部再细分为 Context → Wrapper。


2.3 请求流转路径

结合一次 HTTP 请求来理解 Engine 的作用。假设用户访问:

http://blog.example.com/app/hello

请求流转大致如下:

  1. Connector(如 Http11NioProtocol)接收到请求。

  2. 请求被传递到 Engine

  3. Engine 根据请求头中的 Host: blog.example.com,找到对应的 Host

  4. Host 内部,根据 app 定位到 Context(Web 应用)。

  5. Context 内部,Mapper 会找到 /hello 对应的 Wrapper(Servlet)。

  6. 最终调用 Servlet 的 service() 方法执行逻辑。

📌 Engine 在这里的作用就是 承上启下

  • 上承 Connector 的网络输入

  • 下启 Host/Context/Wrapper 的业务容器


2.4 源码结构剖析

在源码层面,Engine 继承自 Container 接口,而 Container 是所有容器(Engine/Host/Context/Wrapper)的顶层接口。

public interface Container {public String getName();public void setName(String name);public Container getParent();public void setParent(Container container);public Container[] findChildren();
}

Engine 是一个更具体的容器:

public interface Engine extends Container {public String getDefaultHost();public void setDefaultHost(String defaultHost);
}

👉 可以看出,Engine 的特殊性在于:

  • 它的子容器是 Host

  • 它必须有一个默认 Host


2.5 配置中的层级体现

来看一个 server.xml 的简化片段:

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1"/><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" /></Engine></Service>
</Server>

层次结构非常清晰:

  • Server → Service → Engine → Host

  • Connector 独立于容器,但它们和 Engine 一起组成 Service


2.6 类比理解

如果把 Tomcat 类比成一个“快递公司”:

  • Server:快递公司总部

  • Service:一个分公司(有自己的运输队和仓库)

  • Connector:运输队,负责接收外部快递

  • Engine:分公司总仓库,负责快递分拣

  • Host:城市分仓(北京、上海...)

  • Context:区县分仓(海淀区、浦东新区...)

  • Wrapper:具体的投递员(Servlet)

在这个比喻里,Engine 就是大仓库的分拣系统,决定一个快递(请求)应该送到哪一个城市分仓(Host)。


✅ 小结

  • Engine 在分层架构中处于 Service 与 Host 之间,是连接网络层(Connector)与应用层(Context/Wrapper)的关键枢纽。

  • Engine 的唯一性(每个 Service 只能有一个 Engine)保证了请求路由的稳定性。

  • 它的本质作用是 请求分发和容器管理,承载了整个 Tomcat 容器的核心逻辑。

第 3 章:Engine 的生命周期管理(初始化、启动、停止)

3.1 生命周期接口

Tomcat 中所有容器组件(Engine、Host、Context、Wrapper)都实现了 Lifecycle 接口,用来统一管理组件的状态转换。

public interface Lifecycle {String BEFORE_INIT_EVENT = "before_init";String AFTER_INIT_EVENT = "after_init";String START_EVENT = "start";String BEFORE_START_EVENT = "before_start";String AFTER_START_EVENT = "after_start";String STOP_EVENT = "stop";String BEFORE_STOP_EVENT = "before_stop";String AFTER_STOP_EVENT = "after_stop";String DESTROY_EVENT = "destroy";void init() throws LifecycleException;void start() throws LifecycleException;void stop() throws LifecycleException;void destroy() throws LifecycleException;void addLifecycleListener(LifecycleListener listener);
}

📌 关键点

  • 每个阶段都会触发相应的事件(Event),供监听器(Listener)扩展。

  • Engine 作为 ContainerBase 的子类,继承了 Lifecycle 的完整实现。


3.2 生命周期阶段详解

Engine 生命周期主要分为以下几个阶段:

  1. 初始化(init)

    • 初始化容器结构(加载子容器 Host)。

    • 准备 Mapper(请求路径到容器的映射器)。

    • 通知所有注册的 LifecycleListener

  2. 启动(start)

    • 调用 startInternal(),启动自身及子容器(Host → Context → Wrapper)。

    • 启动 Pipeline(责任链)中的 Valve。

    • 触发 START_EVENT

  3. 停止(stop)

    • 调用 stopInternal(),依次停止 Pipeline 和子容器。

    • 回收资源(线程池、缓存、Session 管理器等)。

    • 触发 STOP_EVENT

  4. 销毁(destroy)

    • 释放底层资源。

    • 通知所有监听器。


3.3 源码级解析(Tomcat 10.x)

StandardEngine 为例(继承自 ContainerBase):

@Override
protected void startInternal() throws LifecycleException {// 设置状态为 STARTINGsetState(LifecycleState.STARTING);// 启动子容器(Host)super.startInternal();
}

可以看到,StandardEngine 并没有复杂逻辑,核心都在父类 ContainerBase

ContainerBase.startInternal() 中:

@Override
protected synchronized void startInternal() throws LifecycleException {// 启动 Pipeline(责任链)if (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).start();}// 启动所有子容器(Host)for (Container child : findChildren()) {child.start();}setState(LifecycleState.STARTED);
}

👉 逻辑很清晰:

  1. 先启动 Pipeline(请求处理链)。

  2. 再递归启动所有子容器(Host → Context → Wrapper)。

同理,stopInternal() 过程正好反向:

  • 先停止子容器

  • 再停止 Pipeline

  • 设置状态为 STOPPED


3.4 配置与生命周期的关系

server.xml 中修改 Engine 配置时,通常需要 重启 Tomcat 才能生效。原因就是 Engine 的生命周期被绑定到 Service → Server 的生命周期

例如:

<Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" />
</Engine>

如果修改了 defaultHost,必须重启 Tomcat,因为 Engine.startInternal() 只会在 Service 启动时执行一次。


3.5 生命周期监听器(Listener)

我们可以通过 LifecycleListener 扩展 Engine 的生命周期行为。

示例:自定义一个日志监听器

public class EngineLifecycleLogger implements LifecycleListener {@Overridepublic void lifecycleEvent(LifecycleEvent event) {System.out.println("Engine event: " + event.getType());}
}

server.xml 中挂载:

<Engine name="Catalina" defaultHost="localhost"><Listener className="com.example.EngineLifecycleLogger"/><Host name="localhost" appBase="webapps" />
</Engine>

这样在 Engine 初始化/启动/停止时都会输出日志。


3.6 实际应用场景

  • 多站点动态部署
    如果需要在运行中动态添加新的 Host,必须确保 Engine 已经 start,否则 Host 无法挂载。

  • 灰度发布
    通过 LifecycleListener,可以在 Engine 启动时注册动态配置(如加载灰度路由规则)。

  • 资源回收
    stopdestroy 阶段,可以自定义 Listener 释放数据库连接池、关闭 MQ 客户端等资源。


3.7 常见问题与排查

  1. Engine 未启动导致 404

    • 现象:Connector 正常,但所有请求返回 404。

    • 原因:Engine 或子容器未成功启动(可能是 web.xml 配置错误)。

    • 解决:检查 catalina.out,确认 Engine.startInternal() 是否报错。

  2. 资源未释放导致内存泄漏

    • 现象:Tomcat 重启后内存不断升高。

    • 原因:Engine 停止时未正确调用 destroy(),Listener 或线程池未释放。

    • 解决:实现自定义 LifecycleListener,在 STOP_EVENT 阶段手动清理资源。

第 4 章:Host/Context/Wrapper 容器与 Engine 的关系

4.1 容器层级回顾

在 Tomcat 的容器分层模型中,Engine 作为 Service 内的核心容器,其子容器就是 Host。层级关系如下:

Engine└── Host (虚拟主机)└── Context (Web 应用)└── Wrapper (具体 Servlet)

👉 每一层容器都实现了 Container 接口,因此它们在管理子容器、查找子容器方面保持一致性。


4.2 Engine 与 Host 的关系

  • Engine 的子容器是 Host

    • 每个 Host 对应一个虚拟主机(即域名),支持多站点部署。

    • Engine 通过 defaultHost 属性指定默认 Host,用来处理无法匹配的请求。

  • 源码解析(Engine 添加 Host)
    ContainerBase 中,所有子容器统一管理:

    @Override
    public void addChild(Container child) {child.setParent(this);  // 设置父容器children.put(child.getName(), child); // 存入子容器集合
    }
    

    对于 StandardEngine 来说,这里的 child 就是 Host

  • 配置示例

    <Engine name="Catalina" defaultHost="www.example.com"><Host name="www.example.com" appBase="site1"/><Host name="blog.example.com" appBase="site2"/>
    </Engine>
    
    • www.example.com → 映射到 site1 应用目录

    • blog.example.com → 映射到 site2 应用目录


4.3 Host 与 Context 的关系

  • Host 的子容器是 Context

    • 每个 Context 对应一个 Web 应用(通常是一个 WAR 包)。

    • Host 负责应用的自动部署(autoDeployunpackWARs 参数控制)。

  • 配置示例

    <Host name="localhost" appBase="webapps" autoDeploy="true"><Context path="/app1" docBase="app1"/><Context path="/app2" docBase="app2"/>
    </Host>
    
    • http://localhost:8080/app1 → 访问 app1 应用

    • http://localhost:8080/app2 → 访问 app2 应用

  • 源码解析
    StandardHost 继承 ContainerBase,其 addChild() 方法确保子容器是 Context

    @Override
    public void addChild(Container child) {if (!(child instanceof Context)) {throw new IllegalArgumentException("Child not a Context");}super.addChild(child);
    }
    


4.4 Context 与 Wrapper 的关系

  • Context 的子容器是 Wrapper

    • Context 表示一个 Web 应用,对应 web.xml 中的配置。

    • Wrapper 封装了具体的 Servlet。

  • 配置来源
    web.xml@WebServlet 注解中定义的 Servlet,都会被解析成 Wrapper:

    <servlet><servlet-name>HelloServlet</servlet-name><servlet-class>com.example.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello</url-pattern>
    </servlet-mapping>
    

  • 源码解析(Context 添加 Wrapper)
    StandardContext 中:

    @Override
    public void addChild(Container child) {if (!(child instanceof Wrapper)) {throw new IllegalArgumentException("Child not a Wrapper");}super.addChild(child);
    }
    

    👉 这里的 Wrapper 就是对 HelloServlet 的封装。


4.5 请求逐级下发机制

假设用户访问:

http://blog.example.com/app1/hello

请求路径在容器层级中的映射过程是:

  1. Engine

    • 根据 Host 头(blog.example.com)找到对应的 Host。

  2. Host

    • 根据 URL 的 Context Path(/app1)找到对应的 Context。

  3. Context

    • 根据 Servlet 映射(/hello)找到对应的 Wrapper。

  4. Wrapper

    • 调用目标 Servlet 的 service() 方法处理请求。

📌 这里的 Mapper 组件起到关键作用,它在 Engine 层面维护了 Host → Context → Wrapper 的映射关系。


4.6 类比理解

我们继续用“快递公司”的类比:

  • Engine:总仓库(总分拣中心)

  • Host:城市仓库(北京仓、上海仓)

  • Context:区县仓库(海淀区仓、浦东区仓)

  • Wrapper:快递员(负责具体投递)

👉 请求就像一件快递,在 Engine 的大仓库里首先按城市分拣(Host),再按区县分拣(Context),最后分配给具体快递员(Wrapper)。

第 5 章:责任链模式(Pipeline-Valve)在 Engine 中的实现

5.1 责任链模式简介

责任链模式(Chain of Responsibility)是一种 行为设计模式,允许请求沿着处理链传递,直到某个处理器处理它。

在 Tomcat 中:

  • Pipeline → 责任链的容器

  • Valve → 责任链中的节点,每个 Valve 可以处理请求或将请求传递给下一个 Valve

优势:

  • 灵活可扩展

  • 每个处理器独立,实现关注点分离

  • 支持动态添加/删除处理节点


5.2 Pipeline 与 Valve 的定义

  • Pipeline 接口

    public interface Pipeline {public Valve getBasic();public void setBasic(Valve valve);public void addValve(Valve valve);public void invoke(Request request, Response response)throws IOException, ServletException;
    }
    
  • Valve 接口

    public interface Valve {public void invoke(Request request, Response response, ValveContext context)throws IOException, ServletException;
    }
    

📌 核心思想:

  1. Pipeline 维护一个 Valve 链

  2. 每个 Valve 调用 context.invokeNext() 将请求传递给下一个 Valve

  3. 最后执行 Basic Valve(通常是 Servlet 调用)


5.3 Engine 的 Pipeline 实现

在 Tomcat 中,Engine、Host、Context 都实现了 Pipeline。

public class StandardEngine extends ContainerBase implements Engine, Pipeline {protected Valve basic = null;protected ArrayList<Valve> valves = new ArrayList<>();@Overridepublic void addValve(Valve valve) {valves.add(valve);((ContaineBase) this).pipeline = this;}@Overridepublic void invoke(Request request, Response response)throws IOException, ServletException {((ValveContextImpl) getPipelineContext()).invokeNext(request, response);}
}
  • valves:普通处理节点

  • basic:基础处理节点(最终处理,如将请求交给子容器)


5.4 Pipeline 执行流程

  1. Connector 将请求传递给 Engine

  2. Engine 的 Pipeline 调用第一个 Valve

  3. Valve 执行自己的逻辑(如安全检查、日志记录、过滤器链等)

  4. 调用 context.invokeNext() → 下一个 Valve

  5. 最终调用 Basic Valve → 将请求传递给 Host → Context → Wrapper → Servlet


5.5 配置示例

server.xml 中添加自定义 Valve:

<Engine name="Catalina" defaultHost="localhost"><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 name="localhost" appBase="webapps"/>
</Engine>
  • AccessLogValve 会在请求结束后记录日志

  • 可以自定义多个 Valve,形成责任链


5.6 自定义 Valve 示例

假设我们需要实现请求审计(打印请求 URL 与处理时间):

public class AuditValve implements Valve {@Overridepublic void invoke(Request request, Response response, ValveContext context)throws IOException, ServletException {long start = System.currentTimeMillis();System.out.println("Audit start: " + request.getRequestURI());// 调用下一个 Valvecontext.invokeNext(request, response);long duration = System.currentTimeMillis() - start;System.out.println("Audit end: " + request.getRequestURI() + ", duration=" + duration + "ms");}
}
  • 添加到 Engine:

    Engine engine = (Engine) service.getContainer();
    engine.addValve(new AuditValve());
    

效果:每个请求都会经过 AuditValve 记录日志,然后传递给下一个 Valve。


5.7 Engine Pipeline 与子容器协作

  • Engine Pipeline 只处理 全局逻辑(如日志、安全、负载均衡)

  • Host/Context 的 Pipeline 处理 局部逻辑(如某个应用的过滤器、认证)

  • 责任链是递归执行的:

    • Engine → Host → Context → Wrapper → Servlet

  • 调用顺序举例

    Engine Valve1 → Engine BasicValve → Host Valve2 → Host BasicValve → Context Valve3 → Context BasicValve → Wrapper → Servlet
    


5.8 类比理解

继续用“快递公司”类比:

  • Engine:总分拣中心

    • Valve1:检查包裹重量

    • Valve2:检查地址有效性

  • Host:城市仓库

    • Valve:检查城市路由

  • Context:区县仓库

    • Valve:检查快递员可用性

  • Wrapper:快递员

    • 实际投递

每个环节都是责任链节点,包裹沿链向下流转,最终送达目的地。

第 6 章:请求处理流程(Mapper 定位 → Pipeline 执行 → Servlet 调用)

6.1 请求处理的总体流程

当外部请求进入 Tomcat 时,处理流程大致分为三步:

  1. Mapper 定位

    • Engine 根据请求的 Host 和 URI 找到对应的 Host/Context/Wrapper。

  2. Pipeline 执行

    • 请求沿着 Engine → Host → Context 的 Valve 链执行。

  3. Servlet 调用

    • Wrapper 调用目标 Servlet 的 service() 方法,完成业务逻辑处理。

整个流程可概括为:

Connector → Engine (Pipeline) → Host → Context → Wrapper → Servlet

6.2 Connector 接收请求

Http11NioProtocol 为例:

SocketChannel channel = serverSocket.accept();
Request request = new Request(channel);
Response response = new Response(channel);
processor.process(request, response);
  • Connector 将网络请求封装成 RequestResponse 对象。

  • 请求被传递给 Engine 的 Pipeline 进行处理。


6.3 Engine Mapper 定位

Engine 内部有 Mapper 组件,用于将请求映射到对应的 Host/Context。

源码简化示例(StandardEngine):

Host host = findHost(request.getServerName());
Context context = host.findChild(request.getContextPath());
Wrapper wrapper = context.findChild(request.getServletPath());
  • findHost():根据请求 Host 头找到对应的虚拟主机

  • findChild():在 Host/Context 中查找对应子容器

📌 核心:Engine 只负责找到 Host,Context 和 Wrapper 进一步处理 URL 映射。


6.4 Pipeline 执行

请求定位完成后,通过 Pipeline 执行 Valve 链:

engine.getPipeline().invoke(request, response);

执行逻辑:

  1. Engine Valve1 → Engine Valve2 → Engine BasicValve

  2. Host Valve → Host BasicValve

  3. Context Valve → Context BasicValve → Wrapper.invoke()

  • Engine BasicValve:将请求传给 Host

  • Host BasicValve:将请求传给 Context

  • Context BasicValve:将请求传给 Wrapper(Servlet)


6.5 Wrapper 调用 Servlet

Wrapper 是最底层的容器,封装了 Servlet 实例:

public void invoke(Request request, Response response) throws ServletException, IOException {Servlet servlet = loadServlet();servlet.service(request.getRequest(), response.getResponse());
}
  • loadServlet():延迟加载 Servlet,首次访问时实例化

  • service():调用具体的 doGet()doPost() 方法处理请求


6.6 文字版完整流程描述

假设用户请求 URL:

http://blog.example.com/app1/hello

流程如下:

  1. Connector 接收 TCP 连接,封装 Request/Response

  2. Engine Mapper 查找 Host:blog.example.com

  3. Engine Pipeline 执行全局 Valve(如日志、审计)

  4. Host Mapper 查找 Context:/app1

  5. Host Pipeline 执行局部 Valve(如安全检查)

  6. Context Mapper 查找 Wrapper:/hello → HelloServlet

  7. Context Pipeline 执行应用级 Valve(如请求计时)

  8. Wrapper 调用 Servlet service() 方法

  9. Servlet 处理业务逻辑,写入 Response

  10. Response 返回给 Connector → 返回客户端


6.7 代码片段演示(模拟流程)

// Engine 层
engine.getPipeline().invoke(request, response);// Engine BasicValve
Host host = engine.findHost(request.getServerName());
host.getPipeline().invoke(request, response);// Host BasicValve
Context context = host.findChild(request.getContextPath());
context.getPipeline().invoke(request, response);// Context BasicValve
Wrapper wrapper = context.findChild(request.getServletPath());
wrapper.invoke(request, response);// Wrapper
Servlet servlet = wrapper.loadServlet();
servlet.service(request.getRequest(), response.getResponse());

这个流程展示了 Mapper 定位 + Pipeline 执行 + Servlet 调用 的逐级处理逻辑。


6.8 实际应用场景

  1. 多域名部署

    • Engine Mapper 根据 Host 头路由到不同虚拟主机

  2. 应用隔离

    • Host/Context 层提供独立 Pipeline 和 Wrapper,保证应用隔离

  3. 全局监控

    • Engine Pipeline 可以记录所有请求日志,Host/Context Pipeline 可做性能分析


6.9 小结

  • Engine 负责请求的 路由和全局处理

  • Host/Context 提供 局部处理和应用隔离

  • Wrapper 执行 具体业务逻辑

  • Mapper + Pipeline 是 Tomcat 请求处理链的核心机制

  • 通过源码和文字描述,可以清晰理解请求从 TCP 到 Servlet 的完整路径

第 7 章:Engine 与 Servlet 规范的兼容性

7.1 Servlet 规范概览

Servlet 规范定义了 Java Web 应用的核心接口和行为,包括:

  1. Servlet 接口javax.servlet.Servletjakarta.servlet.Servlet

    • 方法:init() → service() → destroy()

  2. 生命周期管理

    • 容器负责创建 Servlet 实例、调用初始化方法、调用 service() 方法处理请求、最终销毁

  3. 请求/响应对象

    • ServletRequest / ServletResponse 提供 HTTP 请求信息和响应机制

  4. 过滤器链(Filter)

    • 支持请求预处理和后处理

  5. 监听器(Listener)

    • 支持事件感知(如 Session 创建、Context 初始化)

Tomcat Engine 必须支持这些规范,才能保证 Web 应用的可移植性。


7.2 Engine 如何支持 Servlet 生命周期

Engine 通过 Wrapper 承载具体 Servlet,每个 Wrapper 的行为严格遵循 Servlet 规范:

public void invoke(Request request, Response response)throws ServletException, IOException {Servlet servlet = loadServlet();       // 创建或获取 Servlet 实例servlet.service(request.getRequest(), response.getResponse()); // 调用 service
}
  • loadServlet():保证延迟加载,符合 Servlet 生命周期规范

  • Engine/Context/Wrapper 负责管理 Servlet 的 初始化、并发访问、销毁


7.3 请求与响应对象兼容

Tomcat Engine 内部的 RequestResponse 对象封装了 HTTP 协议细节,同时实现了 ServletRequest/ServletResponse 接口

public class RequestFacade implements ServletRequest {private Request request; // 实际请求对象
}
  • 通过 Facade 模式保护内部实现,保证 Web 应用无法直接访问底层容器

  • 支持 Servlet 5.0 新特性,如 HTTP/2 协议、异步处理(AsyncContext


7.4 Pipeline 与 Filter 机制的协作

  • Pipeline 是 Tomcat 的容器级责任链

  • Filter 是 Servlet 规范的应用级责任链

Engine 将请求处理分为两级:

  1. Engine/Host/Context Pipeline:全局/局部容器逻辑

  2. Filter Chain(Context → Wrapper):应用逻辑(如安全、日志、压缩)

示意流程:

Engine Pipeline → Host Pipeline → Context Pipeline → Filter Chain → Servlet.service()
  • 这样既保证了容器级别功能,又兼容标准 Servlet 应用


7.5 支持异步请求(AsyncContext)

Servlet 3.0 及以上规范支持异步请求,Engine 在处理异步请求时也能兼容:

AsyncContext asyncContext = request.startAsync();
asyncContext.start(() -> {servlet.service(request, response);
});
  • Engine 不会阻塞请求线程

  • Pipeline 继续处理其他请求,提高并发能力


7.6 支持 Servlet 注解和 web.xml 配置

Engine 配置的 Context 会解析 Servlet 注解(@WebServlet、@WebFilter)web.xml 文件,自动生成对应 Wrapper/Filter:

Context context = host.findChild("/app1");
context.addChild(new StandardWrapper("HelloServlet", "com.example.HelloServlet"));
  • 自动完成 URL 映射

  • 支持多 Servlet/Filter/Listener,保证与规范一致

第 8 章:Engine 的扩展性(自定义 Valve/Listener)

8.1 Engine 的扩展点概览

Tomcat Engine 提供了两个主要扩展点:

  1. Valve(责任链节点)

    • 插入请求处理责任链

    • 可执行全局或应用级逻辑

    • 示例:日志记录、权限校验、性能监控

  2. Listener(事件监听器)

    • 监听 Engine 生命周期事件

    • 可执行初始化、销毁、启动、停止等操作

    • 示例:资源初始化、动态配置加载


8.2 自定义 Valve

8.2.1 Valve 接口
public interface Valve {void invoke(Request request, Response response, ValveContext context)throws IOException, ServletException;
}
8.2.2 自定义示例:请求计时
public class TimingValve implements Valve {@Overridepublic void invoke(Request request, Response response, ValveContext context)throws IOException, ServletException {long start = System.currentTimeMillis();context.invokeNext(request, response); // 调用下一个 Valvelong duration = System.currentTimeMillis() - start;System.out.println("Request URI: " + request.getRequestURI() + ", Duration: " + duration + "ms");}
}
8.2.3 添加到 Engine
Engine engine = (Engine) service.getContainer();
engine.addValve(new TimingValve());
  • 执行顺序:按照 addValve 的顺序形成责任链

  • Basic Valve:最后执行,将请求传给 Host


8.3 自定义 Listener

8.3.1 LifecycleListener 接口
public interface LifecycleListener {void lifecycleEvent(LifecycleEvent event);
}
8.3.2 示例:Engine 启动日志
public class EngineStartupLogger implements LifecycleListener {@Overridepublic void lifecycleEvent(LifecycleEvent event) {if (Lifecycle.START_EVENT.equals(event.getType())) {System.out.println("Engine started at " + System.currentTimeMillis());}}
}
8.3.3 在 server.xml 中配置
<Engine name="Catalina" defaultHost="localhost"><Listener className="com.example.EngineStartupLogger"/><Host name="localhost" appBase="webapps"/>
</Engine>
  • 当 Engine 启动时,会自动触发 lifecycleEvent,输出启动日志

http://www.dtcms.com/a/337788.html

相关文章:

  • python的电影院座位管理可视化数据分析系统
  • 宋红康 JVM 笔记 Day05|运行时数据区内部结构、JVM中的线程说明、程序计数器
  • linux系统查看ip命令
  • 【自动化测试】Selenium详解-WebUI自动化测试
  • 【智慧工地源码】智慧工地云平台系统,涵盖安全、质量、环境、人员和设备五大管理模块,实现实时监控、智能预警和数据分析。
  • 《清华级防护,了解一下?》
  • 局域网视频软件BeeWorks,内网顺畅沟通
  • FPGA学习笔记——IIC协议简介
  • ​​​​​​​专精特新企业数据(附参考文献, 2013-2023)
  • [openvela] Hello World :从零开始的完整实践与问题复盘
  • linux-高级IO(中)
  • Python数据容器(列表,元组,字典) 从入门到精通
  • 基于Python的就业信息推荐系统 Python+Django+Vue.js
  • 封装,继承,多态
  • 【CV 目标检测】Fast RCNN模型③——模型训练/预测
  • day44_2025-08-18
  • iOS 性能监控全流程实践,从开发到上线的多工具组合方案
  • RabbitMQ ,消息进入死信交换机
  • QT 字节大小端转序方法
  • Qt5基础控件详细讲解
  • VSCode REST Client 使用总结
  • 【力扣-轮转数组 Java / Python】
  • leetcode415. 字符串相加
  • 【论文阅读】-《HopSkipJumpAttack: A Query-Efficient Decision-Based Attack》
  • Jenkins全链路教程——Jenkins调用Maven构建项目
  • 北京朝阳公园——夏日清凉来袭
  • 第7节 神经网络
  • 登上Nature!清华大学光学神经网络研究突破
  • FastAPI + React:现代 Web 前后端分离开发的全栈实践指南
  • 【原理】Unity GC 对比 C# GC