Tomcat执行链(从浏览器到Servlet)

注:本文只关注于请求执行顺序,无初始化过程
高层执行链
浏览器—>http请求–>DNS服务–>三次握手–>tomcat处理–>四次挥手

DNS服务根据域名寻找ip
浏览器缓存–>系统缓存–>路由器缓存–>ISP DNS缓存–>DNS服务器

三次握手
客户端、服务器交换并确认序列号(SYN/ACK)

四次挥手
客户端、服务器双向通知对方结束并确认

Tomcat处理(以Http11NioProtocol为例)
监听端口–>包装Request–>转发到Container–>Servlet

监听端口
connector对象持有ProtocolHandler对象;ProtocolHandler持有AbstractEndpoint对象。AbstractEndpoint负责创建服务器套接字,并绑定到监听端口
NioEndpoint.bind()绑定serverSock监听端口
NioEndpoint
封装底层网络通信细节,提供基础的网络IO服务

Acceptor线程
负责监听serverSock绑定的端口,即循环调用serverSock.accept()获取SocketChannel对象
并将获取到的SocketChannel对象封装为NioChannel对象,并交给Poller线程,将之加入到Poller同步事件队列(PollerEvent队列)
Poller线程
以较少的资源轮询已经连接的套接字并保持连接,当数据可用时将之交给工作线程(而非每个套接字单独绑定一个线程)
每个Poller线程有一个独有的Selector对象(Selector与NioChannel的关系见NIO)
Poller线程会逐个调用PollerEvent线程对象的run()方法,将PollerEvent事件的IOChannel注册到Selector上
再获取Selector中所有已注册的NioChannel对象,逐个执行processKey(SelectionKey, NioSocketWrapper)
在该方法中调用processSocket()方法,封装为SocketProcessor对象,丢到线程池ThreadPoolExecutor中执行

PollerEvent线程队列
重写run()方法不会在单独线程中执行,而是Poller线程中逐个被同步调用
实现Runnable接口,只是用来表示一个轮询事件
run()中将本PollerEvent事件的IOChannel注册到Selector上

SocketProcessor线程
先检查握手,再调用由ConnectionHandler抽象类定义的process()方法
接下来就是由不同协议定义的由socketWrapper转换为Request的具体算法(终于到Request了)
就是这个方法:org.apache.coyote.http11.Http11Processor#service(不想看)
然后这个service中,getAdapter().service(request, response);

CoyoteAdapter
连接Connector与Container的桥梁,转换Request
并转发到Container的管道上,逐级执行阀门,到底层StandardWrapperValve

StandardWrapperValve
封装Servlet,先执行过滤器,再执行servlet
servlet.service(request, response)方法在ApplicationFilterChain内部,执行完过滤器链才会执行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章