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); } }