本流程分析基于 :
springboot 2.1.1Tomcat 9.0.13- 缺省配置
请求处理 : socket => coyote.Request
AbstractProtocal$ConnectionHandler#process(SocketWrapperBase<S> wrapper, SocketEvent status)- 创建一个
Processor Http11Processor : processor = getProtocol().createProcessor()
Http11Processor对象创建 :- 新建
coyote request,response对象 , 这是Tomcat使用的对请求/响应的建模类型 ; - 新建
Http11InputBuffer/Http11OutputBuffer对象,用于作为一对儿请求/响应IO操作的数据缓冲区;
- 新建
processor.service(SocketWrapperBase<?> socketWrapper)
- 创建一个
请求处理 : coyote.Request => HttpServletRequest
-
Http11Processor#service(SocketWrapperBase<?> socketWrapper)处理某个指定的请求
socket socketWrapper,还没有任何请求数据读取;- 使用一个
Http11InputBuffer inputBuffer绑定到socketWrapper,用于处理请求数据; - 使用一个
Http11OutputBuffer outputBuffer绑定到socketWrapper,用于处理响应数据; - 使用
inputBuffer分析Request Line, 头部,相应的分析结果会填充到request/response对象中; - 使用
adapter#service(request,response)进一步处理请求和做出响应;
- 使用一个
-
CoyoteAdapter#service(coyote.Request req,coyote.Response res)- 创建
connector.Request对象,这是一个HttpServletRequest,包装请求参数req; - 创建
connector.Response对象,这是一个HttpServletResponse,包装响应参数rep; - 指定
queryString charset: 缺省UTF-8, postParseRequest(req,request,res,response)connector.getService().getContainer().getPipeline().getFirst().invoke(request, response)
- 创建
-
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response)这里的参数
request,response是HttpServletRequest/HttpServletResponse;
这里的参数request,response已经包装携带了原始的coyote request,response对象 ;
这里的connector在应用启动阶段已经创建,是一个org.apache.catalina.connector.Connector;
这里的connector.getService().getContainer()对应的是一个tomcat StandardEngine对象;
它的pipeline中其实只有一个basic valve:StandardEngineValve
该调用其实继续传递 :host.getPipeline().getFirst().invoke(request, response)
这里的host来自request.getHost(), 它在Adapter中postParseRequest过程中完成 -
host.getPipeline().getFirst().invoke(request, response)- 这里
host的pipeline中有两个Valve:ErrorReportValve和basic valveStandardHostValve - 所以这里的
getFirst()对应的是ErrorReportValve
- 这里
-
ErrorReportValve#invoke(Request request, Response response)getNext().invoke(request, response): 其实是调用StandardHostValve#invoke结合下一步看,这里是先调用下一个
valve,也就是真正的servlet处理,后report错误的做法report(Request request, Response response, Throwable throwable)此方法在响应状态1xx,2xx,3xx时不执行
根据异常throwable和响应状态码response.getStatus()尝试跳转到错误处理页面
如果找不到匹配的错误处理页面,展示一个缺省的错误处理页面(HTML内容在此拼装生成)
-
StandardHostValve#invoke(Request request, Response response)该调用其实继续传递 :
context.getPipeline().getFirst().invoke(request, response)
这里的context来自request.getContext(), 它在Adapter中postParseRequest过程中完成
这里的context.Pipeline()有两个Valve:NonLoginAuthenticator,StandardContextValve
这里的getFirst()对应NonLoginAuthenticator, 缺省情况下它没做任何限制,
NonLoginAuthenticator valve中继续传递调用 :getNext().invoke(request, response) -
StandardContextValve#invoke(Request request, Response response)拒绝访问
/META-INF,/WEB-INF等目录:response.sendError(404)
如果找不到合适的Wrapper, 也就是最终处理者Servlet, 报告错误 :response.sendError(404)
这里如何找到Wrapper, 也就是request属性wrapper是什么时候解析和设置进去的 ???
继续传递请求 :wrapper.getPipeline().getFirst().invoke(request, response) -
wrapper.getPipeline().getFirst().invoke(request, response)这里
wrapper的pipeline其实只有一个basic valve:StandardWrapperValve
获取servlet实例:wrapper.allocate(),这里会对应Spring Web的DispatcherServlet
构建ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet)
相应context上的filterMaps属性是关于url/filter映射关系定义的,这里用来获取所需要应用的Filter,
然后加上request,response,servlet共同构成filterChain
调用filterChain.doFilter(request.getRequest(), response.getResponse())
注意这里getRequest()/getResponse()对应的是RequestFacade/ResponseFacade。这里使用Facade
的目的是可以避免servlet开发环境中访问到一些tomcat底层无关的部分,从而仅仅关注必须要关注的部分。
上面的处理流程,可以认为仍然是Tomcat的处理流程,而非标准的Java Servlet处理流程。假如我们使用的不是Tomcat,而是其他某个Java Servlet容器实现,上面的流程会不一样。但从这一刻开始,也就是从ApplicationFilterChain构造好开始被调用时。可以认为真正的Java Servlet规范定义的Servelt处理流程就要开始了。

本文详细解析了SpringBoot 2.1.1环境下,Tomcat 9.0.13的默认配置中,如何从socket接收请求,到最终由Servlet处理的全过程。包括Http11Processor、CoyoteAdapter的角色及工作原理,以及各层级Valve的调用流程。
1589





