Tomcat架构组成
Tomcat架构组成
Tomcat是一个免费的开放源代码的Servlet容器,Tomcat 容器是对 Servlet 规范的实现,也称为 Servlet 引擎。Tomcat为了更好的处理来自客户端的请求,设计了一套功能完善的处理引擎,其中包括了Container、Engine、Host、Context、Wrapper等模块功能。
从上图可以粗略的分析出他们之间的层级调用关系。
- Server:表示整个 Tomcat Catalina servlet 容器,Server 中可以有多个 Service。
- Service:表示Connector和Engine的组合,对外提供服务,Service可以包含多个Connector和一个Engine。
- Connector:为Tomcat Engine的连接组件,支持三种协议:HTTP/1.1、HTTP/2.0、AJP。
- Container:负责封装和管理Servlet 处理用户的servlet请求,把socket数据封装成Request,传递给Engine来处理。
- Engine:顶级容器,不能被其他容器包含,它接受处理连接器的所有请求,并将响应返回相应的连接器,子容器通常是 Host 或 Context。
- Host:表示一个虚拟主机,包含主机名称和IP地址,这里默认是localhost,父容器是 Engine,子容器是 Context。
- Context:表示一个 Web 应用程序,是 Servlet、Filter 的父容器。
- Wrapper:表示一个 Servlet,它负责管理 Servlet 的生命周期,并提供了方便的机制使用拦截器。
Connector
Connector是Tomcat中的连接器,在Tomcat启动时它将监听配置文件中配置的服务端口,从端口中接受数据,并封装成Request对象传递给Container组件,如下图所示:
tomcat 中 ProtocolHandler 的默认实现类是 Http11NioProtocol,在高版本tomcat中Http11Nio2Protocol也是其中的一个实现类。
ProtocolHandler来处理网络连接和应用层协议,包含两个重要组件:endpoint和processor,endpoint是通信端点,即通信监听的接口,是具体的socket接受和发送处理器,是对传输层的抽象;processor接受来自endpoint的socket,读取字节流解析成Tomcat的request和response对象,并通过adapter将其提交到容器处理,processor是对应用层协议的抽象。总结如下:
- endpoint:处理来自客户端的连接请求。
- processor:接受来自endpoint的socket,读取字节流解析成Tomcat的request和response对象。
- adapter:将封装好的request转交给Container处理,连接Connector和Container。
ProtocolHandler
protocolHandler包含两部分:endpoint和processor;
Endpoint
Endpoint接口,抽象实现类是 AbstractEndpoint,具体子类在 NioEndpoint 和 Nio2Endpoint,其中两个重要组件:Acceptor 和 SocketProcessor。
Acceptor 用于监听 Socket 连接请求,SocketProcessor 用于处理收到的 Socket 请求,提交到线程池 Executor 处理。
Processor
接收 Endpoint 的 socket,读取字节流解析成 tomcat request 和 response,通过 adapter 将其提交到容器处理。Processor 的具体实现类 AjpProcessor、Http11Processor 实现了特定协议的解析方法和请求处理方式。
****
Endpoint 接收到 socket 连接后,生成一个 socketProcessor 交给线程池处理,run 方法会调用 Processor 解析应用层协议,生成 tomcat request 后,调用 adapter 的 service 方法。
Container
在Tomcat中,容器(Container)主要包括四种,Engine、Host、Context和Wrapper。也就是这个图中包含的四个子容器。由下图可以看出,Container在处理请求时使用的Pipeline管道,Pipeline 是一个很常用的处理模型,和 FilterChain 大同小异,都是责任链模式的实现,Pipeline 内部有多个 Valve,这些 Valve 因栈的特性都有机会处理请求和响应。上层的Valve会调用下层容器管道,一步一步执行到FilterChain过滤链。
Context
servletContext负责的是servlet运行环境上下信息,不关心session管理,cookie管理,servlet的加载,servlet的选择问题,请求信息,主要负责servlet的管理。
StandardContext主要负责管理session,Cookie,Servlet的加载和卸载,负责请求信息的处理,掌握控制权。ServletContext主要是适配Servlet规范,StandardContext是tomcat的一种容器,当然两者存在相互对应的关系。
在Tomcat中对应的ServletContext实现是ApplicationContext。Tomcat惯用Facade方式(外观模式),因此在web应用程序中获取到的ServletContext实例实际上是一个ApplicationContextFacade对象,对ApplicationContext实例进行了封装。而ApplicationContext实例中含有Tomcat的Context容器实例(StandardContext实例,也就是在server.xml中配置的Context节点),以此来获取/操作Tomcat容器内部的一些信息,例如获取/注册servlet等。Filter内存马的实现也是基于此知识点获取到了存储在StandardContext中的filterConfigs HashMap结构。
关联关系
从一次服务访问请求探究他们之间的组成关系,如上图所示,配置了HTTP和Ajp两个对外开放端口,同时对应了两个Connector分别负责请求数据包的封包、处理、转发工作,该过程如下图Connector中显示的操作流程。
Connector将解析好的Request对象传递给Container,Container使用Pipeline-Valve管道来处理请求,如下图Pipeline请求流程。直到WrapperValve创建并调用ApplicationFilterChain,最后调用Servlet执行路由处理。
容器通过 Pipeline-Valve 责任链,对请求一次处理,invoke 处理方法,每个容器都有一个 Pipeline,触发第一个 Valve,这个容器的 valve 都会被调到,不同容器之间通过 Pipeline 的 getBasic 方法,负责调用下层容器的第一个 Valve。
整个调用链由连接器中的 adapter 触发,调用 engine 中的第一个 Valve。
// Calling the container connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
wrapper 容器的最后一个 valve 创建一个 filter 链,并调用 doFilter 方法,最终会调用到 servlet 的 service 方法。
final class StandardWrapperValve extends ValveBase { @Override public final void invoke(Request request, Response response) throws IOException, ServletException { // ... ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); // Call the filter chain for this request // NOTE: This also calls the servlet's service() method Container container = this.container; try { if ((servlet != null) && (filterChain != null)) { // Swallow output if needed if (context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch(); } else { // dofilter filterChain.doFilter(request.getRequest(), response.getResponse()); } } finally { String log = SystemLogHandler.stopCapture(); if (log != null && log.length() > 0) { context.getLogger().info(log); } } } else { if (request.isAsyncDispatching()) { request.getAsyncContextInternal().doInternalDispatch(); } else { // dofilter filterChain.doFilter (request.getRequest(), response.getResponse()); } } } } catch() { // ... } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix