前面部分梳理了tomcat服务器处理http请求的一个流程,这里进行内容总结,梳理下在tomcat服务器实现中的,各种功能模块。
[Endpoint]
Endpoint是基础的网络设施,通过Endpoint来实现网络连接和控制,它是服务器对外I/O操作的接入点。主要任务是管理对外的socket连接,同时将建立好的socket连接交到合适的工作线程中去。
content:org.apache.tomcat.util.net.AbstractEndpoint,org.apache.tomcat.util.net.NioEndpoint
对于AbstractEndpoint主要关注它的以下几个属性
private Executor executor = null;
执行业务的线程池,如果外部没有指定线程池,就使用Endpoint内部的线程池
/**
* Threads used to accept new connections and pass them to worker threads.
*/
protected Acceptor[]
acceptors; 管理连接
对于NioEndpoint主要关注它的一下几个属性
/**
* Handling of accepted sockets.
*/
private Handler
handler = null ; 处理socket连接的handler,属于业务处理部分,在executor线程池中执行
/**
* The socket poller.
*/
private Poller[]
pollers = null ; 监听socket事件,调用handler进行socket处理。
它的内部组成包括Poller线程组和Acceptor线程组。
Acceptor线程组负责接收来自外部的网络连接请求,并将建立好的连接,交到Poller线程组去处理。Acceptor的具体工作原理,可以从NioEndpoint$Acceptor.run方法中可以看出,(countUpOrAwaitConnection)控制接收的连接的数量,对接收的连接,(setSocketOptions)将其注册到Poller线程组中,如果在操作过程中遇到错误,则关闭连接。连接注册到Poller线程组后,Poller就能够读取连接中的数据,并进行处理。注册到Poller线程上的效果,是将socket封装后放入Poller线程内部维护的一个PollerEvent队列中,然后Poller线程运行时处理队列,将socket注册到这个Poller的Selector上。
Poller线程组负责对已建立连接的socket进行处理。从NioEndpoint$Poller.run方法中可以看出Poller线程的工作原理,基于Java NIO来进行网络的读写。在run方法中,通过selector.select系列方法来获取数据,然后经由processKey到processSocket方法,封装成一个SocketProcessor对象后,放在EndPoint的线程池中执行,但实际的业务处理部分,是通过Endpoint的Handler进行处理。
[Connection Handler]
处理socket连接的handler
content: Http11ConnectionHandler、AbstractConnectionHandler、AbstractEndpoint.Handler
主要内容部分在AbstractConnectionHandler上,从在这个类中定义的方法上和成员变量上可以看出,它作为一个Handler,但实际上并不直接对socket进行处理。它的主要作用是提供了将Processor和connection进行关联的地方,在适合的地方调用Processor去处理connection。还一个作用是在ConnectionHandler中维护内部缓存来提升系统性能。
在AbstractConnectionHandler的process方法中,实现了对socket的状态检查,缓存数据读写等操作。虽然是在这里对socket进行了各种检查,但并不涉及socket数据的处理,对socket的实际处理,还是交给了Processor来完成。
通过抽象方法 createProcessor方法,来作为关联Processor的入口。通过getProtocol方法,来作为获取和此Connection Handler关联的protocol的入口。
[Socket Processor]
处理socket数据
content: Http11Processor、AbstractHttp11Processor、org.apache.coyote.AbstractProcessor、org.apache.coyote.Processor
Socket Processor是具体处理socket,读写socket数据的地方。
最上层的Processor接口定义了getExecutor、process、event、getRequest等接口,定义了socket processor的大致模型。
getExecutor方法定义了获取处理socket的线程池入口
process方法是处理socket的入口
event处理socket事件的地方
request获取请求来源的入口
次一层的AbstractProcessor定义了Socket Processor框架和其它模块的交互关系,从AbstractProcessor的属性中可以看出
public abstract class AbstractProcessor<S> implements ActionHook,
Processor<S> {
protected static final StringManager sm =
StringManager.getManager(Constants.Package);
protected Adapter adapter;
protected final AsyncStateMachine asyncStateMachine ;
protected final AbstractEndpoint<S> endpoint ;
protected final Request request ;
protected final Response response ;
protected SocketWrapper<S> socketWrapper = null ;
一个Adapter对象,用来和tomcat容器进行关联,这里是实现了和Connector的关联。
Adapter的作用在其注释中描述如下“Adapter. This represents the entry point in a coyote -based
servlet container.”
一个AbstractEndpoint对象,用来和Endpoint模块进行关联,实现对基础网络I/O的屏蔽。
AbstractHttp11Processor中包含了更多的处理http请求相关的细节,包括使用的http协议、socket的维持状态、内容压缩等。同时,更重要的一点是,它实现了process方法,这是整个Socket Processor框架处理http请求的核心部分。从实现的process方法中,可以看出Socket Processor框架的工作原理。 process方法做了各种分支的检查,处理了http请求的各种状态。根据所处理的http请求的状态,设置request和response的状态,最后正常的http请求相关的业务,会交由Adapter的service去进行处理,转移到Connector上来执行。