本流程分析基于 :
springboot 2.1.1
Tomcat 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 valve
StandardHostValve
- 所以这里的
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
处理流程就要开始了。