Spring MVC(2) - DispatcherServlet运行流程
再次看一下类的继承结构
http请求在Servlet的业务处理流程
// Called by the servlet container to allow the servlet to respond to a request.
// javax.servlet.Servlet中定义的接口service,由 servlet container 调用
// 具体实现在HttpServlet类中
public void service(ServletRequest req, ServletResponse res) {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
// HttpServlet类 此方法会将 请求转至 doGet doPost doDelete 等 方法
protected void service(HttpServletRequest req, HttpServletResponse resp){
}
// 类 FrameworkServlet
protected final void doGet(HttpServletRequest request, HttpServletResponse response) {
processRequest(request, response);
}
// 类 FrameworkServlet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) {
try {
// 此方法的实现在子类 DispatcherServlet
doService(request, response);
}
}
// 类 DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response) {
// 核心逻辑
doDispatch(request, response);
}
下面讲 DispatcherServlet的的核心处理流程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// step1, 检查是否是文件上传,如果是,则由相应的bean对request转换
processedRequest = checkMultipart(request);
// step2, 根据request,获取 handler,在初始化过程中,
// 会把url和对应的Controller和method映射关系存好
// 在getHandler过程中,会遍历初始化时注册 HandlerMapping 的bean,
// HandlerMapping会根据自己的规则去获取hander,即Controller和对应的method
// 实际上一般是会遍历映射关系表获取的,获取不到会出错返回
// 这一步还会吧所有的interceptor封装到handler中
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// step3,获取支持第二步中的handler的HandlerAdapter,
// 实际就是从注册HandlerAdapter中选一个支持当前handler的
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 对 Get和Head请求,如果当前HandlerAdapter支持,则处理 last-modified
// step4,应用handler的所有拦截器的preHandle方法,有一个false则返回
// 注意如果有一个拦截器false,则会保证调用所有已经执行的拦截器的afterCompletion方法
// 注意: preHandle 执行顺序 和 postHandle afterCompletion正好相反
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// step5, handleradapter 触发 handler的方法调用,真正的url方法处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 如果view是空,设置默认view
applyDefaultViewName(processedRequest, mv);
// step6, 应用拦截器的 postHandle 方法,
// 注意: postHandle 方法可以处理 ModelAndView
mappedHandler.applyPostHandle(processedRequest, response, mv);
// step7, 对 ModelAndView 进行最后的渲染工作
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException) {
// 进行渲染工作,具体过程为 使用Servlet初始化时注册的 ViewResolver,比如 InternalResourceViewResolver
// 根据viewName,生成不同的view对象(通常是AbstractUrlBasedView子类 InternalResourceView )
// 其中,会对viewName中的 “redirect:xx” 和 “forward:xx” 生成不通view类
// 然后进行view类的属性填充,比如 suffix 和 prefix 加到url并设置到view类的属性中
// View类具体处理是,最终会把Model中的属性设置到request中,根据url找到对应的RequestDispather
// RequestDispather会把当前request和response关联到对应的资源,即Jsp文件
render(mv, request, response);
// 进行拦截器的afterCompletion调用
mappedHandler.triggerAfterCompletion(request, response, null);
}
// 最外侧的catch仍然保证拦截器的afterCompletion调用
catch(Excepton e) {
// 进行拦截器的afterCompletion调用
mappedHandler.triggerAfterCompletion(request, response, null);
}
}