Tomcat源码分析(2)-连接器Connector整体架构
在上一篇博文中,主要分析了tomcat的整体架构,通过上一篇的分析可以知道,tomcat主要有两部分组成,分别为连接器(Connector)和容器(Container)。本文介绍连接器(Connector)。
一、Connector的主要功能
连接器主要用于对外交流,它负责接收外部的请求,然后把请求转交给container进行处理。主要功能如下:
- 监听网络请求、接受字节流
- 根据应用层协议(HTTP or AJP)把接受到字节流转换成TomcatRequest
- 把TomcatReqeust转换成ServletRequest
- 调用容器Servlet,得到ServletResponse
- 把ServletRespone转换成TomcatResponse
- 把TomcatResponse转化成字节流,返回给浏览器
基于以上详细分析可知Connector的主要功能可以抽象为三点
- 网络监听
- 协议解析处理
- 协议屏蔽转换(tomcatRequest到servletReqeust转换,servletResponse到tomcatResponse的转换)
二、Connetor内部的组件
基于上述的分析,接下来具体看tomcat connector的代码组件,主要有三个
- Endpoint-用于网络监听
- Processor-用于协议解析处理
- Adapter-用于转换,解耦connector和container
tomcat的类设计中增加了一个ProtocolHandler, 把Endpoint和Processor,Adapter封装到了一起。先看一个整体组件图。
三、Endpoint介绍
Endpoint是通信节点,实现了TCP/IP协议,包含两个核心组件:
- Acceptor,主要用于监听socket链接请求,
- SocketProcessor,用于处理接收到的 Socket 请求,实现了runnable接口,在run方法中会调用processor对socket请求进行处理。
Endpoint核心接口
public abstract class AbstractEndpoint<S> { protected Acceptor[] acceptors; protected abstract SocketProcessorBase<S> createSocketProcessor( SocketWrapperBase<S> socketWrapper, SocketEvent event); protected SynchronizedStack<SocketProcessorBase<S>> processorCache; /** * External Executor based thread pool. */ private Executor executor = null; }
这里面还有一个Executor, 这个是tomcat自己扩展的线程池。Acceptor监听到socket请求后,创建SocketProcessor,由Executor来运行SocketProcessor。
Acceptor核心代码:
protected class Acceptor extends AbstractEndpoint.Acceptor { @Override public void run() { while (running) { state = AcceptorState.RUNNING; try { //Accept the next incoming connection from the server SocketChannel socket = serverSock.accept();//监听请求 //setSocketOptions() will hand the socket off to an appropriate processor if successful setSocketOptions(socket);//把请求传给SocketProcessor } catch (Throwable t) { } } } }
setSocketOption最终会调用Endpoint的process方法。
Endpoint的process核心方法代码如下:
public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) { SocketProcessorBase<S> sc = processorCache.pop(); if (sc == null) { sc = createSocketProcessor(socketWrapper, event);//创建SocketProcessor } else { sc.reset(socketWrapper, event); } Executor executor = getExecutor(); executor.execute(sc);//交给线程池进行处理 return true; }
SocketProcessor的抽象类
public abstract class SocketProcessorBase<S> implements Runnable { protected SocketWrapperBase<S> socketWrapper; protected SocketEvent event; @Override public final void run() { synchronized (socketWrapper) { if (socketWrapper.isClosed()) { return; } doRun(); } } protected abstract void doRun(); }
SocketProcessor类
protected class SocketProcessor extends SocketProcessorBase<NioChannel> { public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) { super(socketWrapper, event); } @Override protected void doRun() { NioChannel socket = socketWrapper.getSocket(); SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL); } }
上面类中getHandler().process的具体实现。(Handler的接口由Endpoint的内部类进行定义。
protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> { private final Map<S, Processor> connections = new ConcurrentHashMap<>(); @Override public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) { S socket = wrapper.getSocket(); Processor processor = connections.get(socket); return processor.process(wrapper, status); } }
至此、请求已经成功传给可processor。
三、processor、adapter
processor是应用层协议比如HTTP的处理。他负责把请求传给adapter。核心代码如下。
@Override public SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException { try { getAdapter().service(request, response); } catch (Exception e) { e.printStackTrace(); } return null; }
adapter解耦了connector和container的关系,主要负责把tomcatRequest转换为servletRequest,然后最终调用container,核心代码如下。
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); } // Calling the container connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); }
至此请求到达了container,我们的servlet会对进行业务逻辑处理。
四、细化流程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix