一、连接器的调用过程
参考资料
https://time.geekbang.org/column/article/100307
https://juejin.cn/post/6844903626175954952
1.生产消费者模式
生产者:Acceptro开启一个线程(Springboot的内嵌tomcat)监听连接请求(只是TCP连接,不包括请求)。生成的SocketChannel,添加到队列中EventQuen中,当队列长度达到8*1024时,就不从内核态的ACCPET队列里获取 。
- TCP三次握手建立连接的过程中,内核通常会为每一个LISTEN状态的Socket维护两个队列:SYN队列(半连接队列):这些连接已经接到客户端SYN;ACCEPT队列(全连接队列):这些连接已经接到客户端的ACK,完成了三次握手,等待被accept系统调用取走。
- Acceptor负责从ACCEPT队列中取出连接,当Acceptor处理不过来时,连接就堆积在ACCEPT队列中,这个队列长度也可以通过参数设置。
消费者:Poller,从队列里消费SocketChannel
2.AQS使用 LimitLatch
连接数达到8*1024,则Acceptor线程挂起。
释放连接,换起线程。
3.NIO的使用
略
4.线程池拓展
Tomcat 在线程总数达到最大数时,不是立即执行拒绝策略,而是再尝试向任务队列添加任务,添加失败后再执行拒绝策略
https://blog.csdn.net/mulinsen77/article/details/84583716
https://javadoop.com/post/AbstractQueuedSynchronizer
5.IO模型
I/O 模型是为了解决内存和外部设备速度差异的问题。我们平时说的阻塞或非阻塞是指应用程序在发起 I/O 操作时,是立即返回还是等待。而同步和异步,是指应用程序在与内核通信时,数据从内核空间到应用空间的拷贝,是由内核主动发起还是由应用程序来触发。
6.Acceptor的一些疑问
断点打在Acceptor的run方法的while循环内为什么不会一直跑着?
答案:会一直跑着,但代码会阻塞在接收socket的方法上,直到有新的连接进来唤醒线程。
二、容器的调用过程
- 容器的调用
使用Pipeline-Value。每个容器都有一个Pipeline,只要触发这个Pipeline的第一个Value,这个容器里的pipeline里的Value都会被调用到。
不同容器的 Pipeline 是怎么链式触发的呢,比如 Engine 中 Pipeline 需要调用下层容器 Host 中的 Pipeline。这是因为 Pipeline 中还有个 getBasic 方法。这个 BasicValve 处于 Valve 链表的末端,它是 Pipeline 中必不可少的一个 Valve,负责调用下层容器的 Pipeline 里的第一个 Valve。
基础筏
StandardEngineValve
StandardHostValve
StandardContextValve
StandardWrapperValve - 什么是Value
Valve 表示一个处理点,比如权限认证和记录日志。Valve 完成自己的处理后,调用getNext.invoke来触发下一个 Valve 调用。
public interface Valve {
//链表将他们串起来
public Valve getNext();
public void setNext(Valve valve);
//处理请求
public void invoke(Request request, Response response)
}
public interface Pipeline extends Contained {
//维护value链表
public void addValve(Valve valve);
public Valve getBasic();
public void setBasic(Valve valve);
public Valve getFirst();
}
-
为什么会有Wrapper
Servlet有多个实例,Context 容器直接维护一个 Servlet 数组不就行了吗?这是因为 Servlet 不仅仅是一个类实例,它还有相关的配置信息,比如它的 URL 映射、它的初始化参数,因此设计出了一个包装器,把 Servlet 本身和它相关的数据包起来,没错,这就是面向对象的思想。 -
总结
请求的链式调用是基于 Pipeline-Valve 责任链来完成的,这样的设计使得系统具有良好的可扩展性,如果需要扩展容器本身的功能,只需要增加相应的 Valve 即可。
Wrapper持有servlet实例
public synchronized Servlet loadServlet() throws ServletException {
Servlet servlet;
//1. 创建一个Servlet实例
servlet = (Servlet) instanceManager.newInstance(servletClass);
//2.调用了Servlet的init方法,这是Servlet规范要求的
initServlet(servlet);
return servlet;
}