整体架构图

一. 启动阶段

BootStrap的main方法加载server.xml配置文件,封装成Server,Service,Connector,Engine等java对象

Server初始化==>Service初始化==>Connector初始化==>Engine初始化==>Host初始化==>Context初始化 WAR解压 创建Servlet

Connector初始化:绑定端口,创建BIO NIO NIO2线程池

Connector.setProtocol是在解析server.xml配置文件时绑定关系

启动Connector initInternal() ===>ProtocolHandler.init() ==> Endpoint.init()-->Endpoint.bind()

Connector作用(接收请求时):

ServerSocket(Channel)接收socket请求创建Socket, 并将Socket.InputStream中的内容封装成javax.servlet.http.HttpServletRequest的实现类, 经过多个valve filter之后传递到Container的Servlet(SpringMVC)中, servlet.doService完成之后由HttpServletResponse(持有请求时创建的socket?).outputStream回写内容到socket中

Protocol 配置在server.xml的<connector >标签的属性中, 作用:根据配置创建不同的Endpoint

tomcat8.5

Endpoint 具体协议的实现, 完成绑定端口及创建线程池

tomcat8.5

tomcat8.0 

tomcat 7.0

Endpoint.startInternal()

7.0默认使用JIOEndpoint, 8.0以上默认使用NIOEndpoint

//搞懂NIO NIO2===>

二、接收浏览器HTTP请求

整体流程:

NIOEndpoint ---> Http11Processor(创建Request, Response) ---> CoyoteAdapter --> Container -->

PipeLine(StandardEngineValve, StandardHostValve, StandardContextValve, StandardWrapperValve)--> Servlet.doService

2.1 Endpoint中request创建

JIOEndpoint在接收socket请求后,直接将Request交给了worker线程

NIOEndpoint.Acceptor在接收到请求后(while循环一直监听),将PollerEvent事件注册到NIOEndpoint.Poller(持有selector对象)的事件队列中,并调用selector.waitup() 只调用一次,

private void addEvent(PollerEvent event) {
events.offer(event);
if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
}

Poller的while循环中查找到PollerEvent, 调用processKey()方法-->AbstractEndpoint#processSocket()在这里创建SocketProcessor(Runable)并提交给Executor线程池处理。

SocketProcessor --> Http11Processor.service() readsocket&buildRequest-->CoyoteAdatper.service()

2.2 CoyoteAdapter中处理Request

Servlet3.1 异步Request, 在Servlet里面设置.isAsync, coyoteAdapter invoke服务方法后直接返回,socket并没有释放

org.apache.catalina.connector.CoyoteAdapter#service

             if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container 调用filter servlet
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
if (request.isAsync()) {
async = true;
ReadListener readListener = req.getReadListener();
if (readListener != null && request.isFinished()) {
// Possible the all data may have been read during service()
// method so this needs to be checked here
ClassLoader oldCL = null;
try {
oldCL = request.getContext().bind(false, null);
if (req.sendAllDataReadEvent()) {
req.getReadListener().onAllDataRead();
}
} finally {
request.getContext().unbind(false, oldCL);
}
} Throwable throwable =
(Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); // If an async request was started, is not going to end once
// this container thread finishes and an error occurred, trigger
// the async error process
if (!request.isAsyncCompleting() && throwable != null) {
request.getAsyncContextInternal().setErrorState(throwable, true);
}
} else {
request.finishRequest(); // 非异步的请求处理之后, 会释放socket
response.finishResponse();
}

session创建时机, 在Request.getSession时根据请求中的JSESSIONID查找,如果id为null,首次创建,新的请求中就携带了JSESSIONID

Connector创建的是org.apache.catalina.connector.Request

org.apache.catalina.core.StandardWrapperValve --> 具体某个Servlet (DispatchServlet),  初始化FilterChain, 然后调用各个filter, 最后到Servlet.doService

filterChain.doFilter
(request.getRequest(), response.getResponse());

压缩版的两个默认Servlet: DefaultServlet处理静态资源,JSPServlet创建HttpServletRequest,对connector.Request又包一层

2.3 Response的socket WRITE,CLOSE事件在NIOEndpoint中的处理

和socket OPEN_READ事件基本一致

其他参考:

Http中socket长连接短连接使用场景 http://www.cnblogs.com/0201zcr/p/4694945.html

程序中设置为长连接 1. socket.setKeepAlive(true)   2.socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);

See:

http://tomcat.apache.org/tomcat-8.0-doc/architecture/requestProcess.html

http://tomcat.apache.org/tomcat-8.0-doc/config/http.html#NIO2_specific_configuration

最新文章

  1. 为什么 Java 8 中不再需要 StringBuilder 拼接字符串
  2. Multiple types were found that match the controller named &#39;Home&#39;. (weird error)
  3. Y2K Accounting Bug(贪心)
  4. 【LeetCode OJ】Word Ladder I
  5. Hibernate与MyBatis区别
  6. Go Mobile 例子 audio 源码分析
  7. 轻松学习Linux之VI编辑器的使用
  8. POJ 1811Prime Test(米勒拉宾素数测试)
  9. hibernate 映射&lt;五&gt;多对多双向映射
  10. block(四)揭开神秘面纱(下)
  11. Android的BUG(一) - HTML 5 播放streaming video造成卡住的问题
  12. 我的小OJ
  13. JVM难学?那是因为你没认真看完这篇文章
  14. 中间件(3)NoSQL
  15. Shell 对整个文件夹中的文件进行MD5校验 [转]
  16. 【Git】Git中的冲突(图形界面,待更新...)
  17. Web 呼起 APP
  18. base64详解及实现
  19. Linux 标准目录结构 FHS
  20. css 渐变动画

热门文章

  1. 51nod 1686 第K大区间2
  2. Anthem.NET的 &quot;Bad Response&quot; 问题,及脚本调试技巧小结
  3. Hyperledger fablic 0.6 在centos7环境下的安装与部署
  4. 如何利用pyenv 和virtualenv 在单机上搭建多版本python 虚拟开发环境
  5. Java常见设计模式之观察者模式
  6. 第二课 go语言的结构
  7. 【转】Ruby on Rails中select使用方法
  8. Python-Redis的Hash操作
  9. C语言学习笔记--const 和 volatile关键字
  10. Qt 按顺序保存多个文件