从Tomcat到SpringMVC
作为过渡篇,本文以Tomcat服务器为例,讲讲请求是如何从Tomcat来到SpringMVC的(Springboot环境下)
1.回顾
SpringMVC的核心是DispatcherServlet. 而DispatcherServlet的本质还是一个Servlet 。
说到Servlet 就得讲讲web服务器Tomcat。
文接Tomcat原理系列之三:请求链上的那些类 与 Tomcat原理系列之七:详解socket如何封装成request(下)
2.请求从Tomcat到SpringMVC
请求通过Socket 开启应用之旅,在Tomcat原理系列之三:请求链上的那些类 中讲过,请求来到Tomcat的最后一个valve,StandardWrapperValve时。执行其invoke方法
StandardWrapperValve
请求来到StandardWrapperValve#invoke方法
final class StandardWrapperValve
extends ValveBase {
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// 1.Allocate a servlet instance to process this request
//分配一个servet 去处理请求
servlet = wrapper.allocate();
// 2.Create the filter chain for this request
//封装servlet, 为当前请求创建一个过滤器链
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
//3.执行过滤器链的doFilter方法,(链式执行各种Filter ,末端执行servlet's service() method)
filterChain.doFilter(request.getRequest(),
response.getResponse());
}
}
ApplicationFilterChain
之后来到 ApplicationFilterChain#doFilter方法
public final class ApplicationFilterChain implements FilterChain {
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
internalDoFilter(request,response);//调用内部internalDoFilter方法
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
// 4.链式调用每个Filter的doFilter方法
if (pos < n) {
filter.doFilter(request, response, this);
}
//5.调用servlet的service方法
servlet.service(request, response);
}
}
在Filter的末端,开始准备进入Servlet执行方法。
HttpServlet
我们来看看DispatcherServlet 的继承图
从图中我们可以看出,DispatcherServlet 通过几层父类间接实现Servlet。
ApplicationFilterChain中 调用servlet.service(request, response);传递的参数是(ServletRequest request, ServletResponse response)。所以执行的是HttpServlet 中的service方法.可以看出此方法的目的是将ServletRequest,ServletResponse 转换为我们熟悉的HttpServletRequest ,HttpServletResponse
public abstract class HttpServlet extends GenericServlet {
//6.执行HttpServlet.service()方法,做req,res 的强制转换
public void service(ServletRequest req, ServletResponse res){
HttpServletRequest request;
HttpServletResponse response;
try {
//转为 HttpServletRequest,HttpServletResponse
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
//8.执行HttpServlet.service此时的参数已经是HttpServletRequest,HttpServletResponse
//并根据请求方法类型。调用不同的处理方法。子类FrameworkServlet 类中重写了一些方法,所以转去执行子类的doGet方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (method.equals(METHOD_GET)) {
doGet(req, resp);
}
}
}
FrameworkServlet
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
//7.兼容PATCH方法,非PATCH方法最终还是交给HttpServlet.service()
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
//9.get代理方法,转到processRequset去处理
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
//10.模板方法,请求的处理交给子类的doService方法去处理
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doService(request, response);
}
}
DispatcherServlet
最终请求来到了DispatcherServlet的doService方法,开始DispatcherServlet的工作内容
//最终来到了DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
//11.做请求分发前的准备工作,主要是设置一些请求的相关属性
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
doDispatch(request, response);
}
//12 开启请求的分发。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//开启DispatcherServlet的分发功能
}
}
最终请求到了DispatcherServlet的doDispatch开启DispatcherServlet 请求分发处理功能。
3.DispatcherServlet的工作原理
请求到达doDispatch 方法后,DispatcherServlet对其做了什么呢?这就引出了DispatcherServlet的工作原理这个话题。
处理流程
借用网上张图:
- 请求来到DispatcherServlet
- DispatcherServlet根据请求信息,从HandlerMapping 找能处理当前请求的Handler并封装成一个HandlerExecutionChain
- 根据解析到的Handler ,获取一个适配器。
- HandlerAdapter会根据Handler来调用真正的处理器开处理请求,列如我们写的controller类中的业务方法
- 处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View
- ViewResolver会根据逻辑View查找实际的View。
- 视图渲染完成后,DispatcherServlet返回。
这些流程反映在代码中,就是doDispatch 方法内的相关调用了.
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//检查是否是上传文件请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取能处理当前请求的Handler 链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取能处理当前请求的的handler的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//拦截器前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//适配器handle方法处理请求。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//拦截器后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
4.总结
我们可以看出,DispatcherServlet采用了“中心化”的思想。请求统一过DispatcherServlet,这样的好处就是统一管理。DispatcherServlet就有点路由的意思了。
本文衔接Tomcat原理系列之七:详解socket如何封装成request(下) 终于粗略的过了一遍,请求如何从socket经Tomcat到达DispatcherServlet,变成我们常用的HttpServletRequest 。对于web 的工作原理有了更深的理解
明白道理不一定能让我们技术增进多少,但至少心里不疑惑。
如果本文任何错误,请批评指教,不胜感激 !
微信公众号:源码行动
享学源码,行动起来,来源码行动