Spring MVC 基于模型-视图-控制器(Model-View-Controller, MVC)模式实现,并且很好的实现了软件设计中的开闭原则(即对扩展开放,对修改关闭),当因为业务需要对Spring MVC做些定制化处理时,就会发现Spring MVC对功能扩展是极其友好的、在后续的源码解析系列文章中我们会陆续看到Spring MVC在处理请求的各个步骤中都可以定制所需要的功能。
整个系列的文章都会围绕这张图进行,会对每一个步骤进行详细讲解。 首先我们先来看一下 DispatcherServlet diagram
可以看到蓝色的继承关系到 Servlet 相信大家在学习 MVC
框架之前对 HttpServlet
非常的熟悉,目前还有一些老项目在使用原生的 java servlet
进行项目开发。我们看一下 servlet
接口最重要的方法签名:
/** * Called by the servlet container to allow the servlet to respond to * a request. * * <p>This method is only called after the servlet's <code>init()</code> * method has completed successfully. * * <p> The status code of the response always should be set for a servlet * that throws or sends an error. * * * <p>Servlets typically run inside multithreaded servlet containers * that can handle multiple requests concurrently. Developers must * be aware to synchronize access to any shared resources such as files, * network connections, and as well as the servlet's class and instance * variables. * More information on multithreaded programming in Java is available in * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html"> * the Java tutorial on multi-threaded programming</a>. * * * @param req the <code>ServletRequest</code> object that contains * the client's request * * @param res the <code>ServletResponse</code> object that contains * the servlet's response * * @exception ServletException if an exception occurs that interferes * with the servlet's normal operation * * @exception IOException if an input or output exception occurs * */ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
这个方法是 servlet
处理 web
请求的入口。 Spring MVC
在 DispatchSerlvet
还分装了一层 FrameWorkServlet
用于统一处理所有不同方法类型( GET
、 POST
等)的请求
我们从一个 Http
请求的角度,来大致了解Spring MVC是处理请求的大致流程(例如,到 controller
方法加 @ResponseBody
时就不会有视图解析这一步)。
1、web container 接收到一个请求,容器调用已经注册好的 DispatcherServlet
,后者通过 Request
对象到 RequestMapping
获取对应的 handler
(即 controller
层实际调用的方法)。
2、执行 interceptor
的 preHandler()
方法。
3、执行第一步获取的 Controller
方法,并返回 ModelAndView
。
4、执行 interceptor
的 postHandler()
方法。
5、视图渲染,执行ViewResolve.resolveViewName()方法回去视图文件。
/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ 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 { //判断请求是否是 multipart post (常见的有 post 表单提交的数据) processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. //通过request获取handler,包括 intercepter 信息 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //获取 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; } } //调用 intercepter.perHandler()方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. //调用controller方法发挥 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //当 ModelAndView 中不包含视图时获取默认视图 applyDefaultViewName(processedRequest, mv); //调用 intercepter.perHandler()方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } //视图渲染并将渲染后的视图文件(html)或者 json 等写入Response body 返回给浏览器 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); } } } }
本文主要介绍了Spring MVC的一些概念以及请求执行的大致过程。后续的文章将继续分析Spring MVC的各个组件,以及如何根据自己的项目定制相应的功能。