Spring MVC源码深入剖析执行流程

来源:互联网 发布:淘宝 做工粗糙 有瑕疵 编辑:程序博客网 时间:2024/05/19 01:13
Spring MVC是现在最流行的MVC框架, 很多人说它是一个优秀的框架。实质上是由于Spring MVC加入注解,注解让Spring MVC质变, 这使得开发效率得到了飞速提升。而且它本身就是Spring的一小部分,所以让就不再像Struts2那样,需要插件的支持。也就是说,它们是无缝连接的。但无论多少多么优秀的框架,它们永远都是建立在listener, servlet, filter这些服务器容器组件之上的。可见基础尤其重要。

首先, 如果我们想在Web项目中添加Spring MVC的支持,要在web.xml中配置如下代码:

[html] view plaincopy
  1. <servlet>  
  2.     <servlet-name>springMVC</servlet-name>  
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.     <load-on-startup>1</load-on-startup>  
  5. </servlet>  

其中,org.springframework.web.servlet.DispatcherServlet就是整个Spring MVC框架的切入点。与添加Struts类似。Struts是通过Filter作为切入点,而Spring MVC使用的是Servlet。原理其实是一样的,都起到拦截用户请求的作用。Filter是在服务器启动时,即生成一个实例。而Servlet若不设置load-on-startup,则为第一次访问时生成实例。DispatcherServlet需要在服务器启动时生成实例。

下面我们通过源码的来解析Spring MVC的大体流程:

[java] view plaincopy
  1. //这是DispatcherServlet的定义,继承自FrameworkServlet  
  2. public class DispatcherServlet extends FrameworkServlet {  
  3. ...  
  4.     protected void initStrategies(ApplicationContext context) {  
  5.         ...  
  6. }  
  7.   
  8. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  9. ...  
  10. }  
  11. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  12. ...  
  13. }  
  14. ...  
  15.   
  16. }  

  当我们发送请求时,DispatcherServlet会进行拦截,而对于Servlet来说。service方法是处理请求的核心,但DispatcherServlet中并没有定义此方法。我们通过父类FrameworkServlet中查看:

[java] view plaincopy
  1. protected void service(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.   
  4.         String method = request.getMethod();  
  5.         if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {  
  6.             processRequest(request, response);  
  7.         }  
  8.         else {  
  9.             super.service(request, response);  
  10.         }  
  11.     }  

  processRequest(request,response)方法调用,在这个方法中,调用的了doService(request,response)。而此时doService正是上述的DispatcherServlet中的doService方法。而doService中又调用了doDispatcher方法。那么可以看出,doDispatcher就是DispatcherServlet处理核心方法。

下面为doDispatcher方法的源码:

[java] view plaincopy
  1. <span style="white-space:pre">    </span>/** 
  2.      * Process the actual dispatching to the handler. 
  3.      * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. 
  4.      * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters 
  5.      * to find the first that supports the handler class. 
  6.      * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers 
  7.      * themselves to decide which methods are acceptable. 
  8.      * @param request current HTTP request 
  9.      * @param response current HTTP response 
  10.      * @throws Exception in case of any kind of processing failure 
  11.      */  
  12.     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  13.         HttpServletRequest processedRequest = request;  
  14.         HandlerExecutionChain mappedHandler = null;  
  15.         boolean multipartRequestParsed = false;  
  16.   
  17.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  18.   
  19.         try {  
  20.             ModelAndView mv = null;  
  21.             Exception dispatchException = null;  
  22.   
  23.             try {  
  24.                 processedRequest = checkMultipart(request);  
  25.                 multipartRequestParsed = processedRequest != request;  
  26.   
  27.                 // Determine handler for the current request.  
  28.                 mappedHandler = getHandler(processedRequest, false);  
  29.                 if (mappedHandler == null || mappedHandler.getHandler() == null) {  
  30.                     noHandlerFound(processedRequest, response);  
  31.                     return;  
  32.                 }  
  33.   
  34.                 // Determine handler adapter for the current request.  
  35.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  36.   
  37.                 // Process last-modified header, if supported by the handler.  
  38.                 String method = request.getMethod();  
  39.                 boolean isGet = "GET".equals(method);  
  40.                 if (isGet || "HEAD".equals(method)) {  
  41.                     long lastModified = ha.getLastModified(request, mappedHandler.getHandler());  
  42.                     if (logger.isDebugEnabled()) {  
  43.                         logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);  
  44.                     }  
  45.                     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {  
  46.                         return;  
  47.                     }  
  48.                 }  
  49.   
  50.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
  51.                     return;  
  52.                 }  
  53.   
  54.                 try {  
  55.                     // Actually invoke the handler.  
  56.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  57.                 }  
  58.                 finally {  
  59.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  60.                         return;  
  61.                     }  
  62.                 }  
  63.   
  64.                 applyDefaultViewName(request, mv);  
  65.                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
  66.             }  
  67.             catch (Exception ex) {  
  68.                 dispatchException = ex;  
  69.             }  
  70.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  71.         }  
  72.         catch (Exception ex) {  
  73.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
  74.         }  
  75.         catch (Error err) {  
  76.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
  77.         }  
  78.         finally {  
  79.             if (asyncManager.isConcurrentHandlingStarted()) {  
  80.                 // Instead of postHandle and afterCompletion  
  81.                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
  82.                 return;  
  83.             }  
  84.             // Clean up any resources used by a multipart request.  
  85.             if (multipartRequestParsed) {  
  86.                 cleanupMultipart(processedRequest);  
  87.             }  
  88.         }  
  89.     }  

  首先有几个类需要声明,ModelAndView、HandlerExecutionChain、HandlerMapping、HandlerMethod、HandlerAdapter。

 

1、HandlerMethod(org.springframework.web.method.HandlerMethod),这个类为中存放了某个bean对象和该bean对象的某个要处理的Method对象。

2、HandlerMapping,作用为通过request对象,获取对应的HandlerMethod对象。

3、HandlerExecutionChain作用为通过加入Interceptor拦截器包装HandlerMapping返回的HandlerMethod对象。让待处理的方法对象与拦截器称为一个整体,即执行链。

4、ModelAndView,顾名思义。Model即MVC的M,View即MVC的V。其对象存放的正是数据与视图信息。

5、HandlerAdapter:作用为具体处理HandlerMethod,即通过它调用某个方法。

下面分析正题:

doDispatcher方法中,首先通过getHandler方法获得handler,如下:

[java] view plaincopy
  1. <span style="white-space:pre">    </span>/** 
  2.      * Return the HandlerExecutionChain for this request. 
  3.      * <p>Tries all handler mappings in order. 
  4.      * @param request current HTTP request 
  5.      * @return the HandlerExecutionChain, or {@code null} if no handler could be found 
  6.      */  
  7.     protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  8.         for (HandlerMapping hm : this.handlerMappings) {  
  9.             if (logger.isTraceEnabled()) {  
  10.                 logger.trace(  
  11.                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");  
  12.             }  
  13.             HandlerExecutionChain handler = hm.getHandler(request);  
  14.             if (handler != null) {  
  15.                 return handler;  
  16.             }  
  17.         }  
  18.         return null;  
  19.     }  
遍历所有HandlerMapping并调用每个HandlerMapping对象的getHandler方法,而HandlerMapping为接口,其中AbstractHandlerMapping这个抽象类中实现了HandlerMapping接口,并实现了getHandler方法,如下:

[java] view plaincopy
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {  
  2.         Object handler = getHandlerInternal(request);  
  3.         if (handler == null) {  
  4.             handler = getDefaultHandler();  
  5.         }  
  6.         if (handler == null) {  
  7.             return null;  
  8.         }  
  9.         // Bean name or resolved handler?  
  10.         if (handler instanceof String) {  
  11.             String handlerName = (String) handler;  
  12.             handler = getApplicationContext().getBean(handlerName);  
  13.         }  
  14.         return getHandlerExecutionChain(handler, request);  
  15.     }  
其中Object handler = getHandlerInternal(request);为获取HandlerMethod对象,此方法源码如下:

[java] view plaincopy
  1. <span style="white-space:pre">    </span>/** 
  2.      * Look up a handler method for the given request. 
  3.      */  
  4.     @Override  
  5.     protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {  
  6.         String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);  
  7.         if (logger.isDebugEnabled()) {  
  8.             logger.debug("Looking up handler method for path " + lookupPath);  
  9.         }  
  10.         HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);  
  11.         if (logger.isDebugEnabled()) {  
  12.             if (handlerMethod != null) {  
  13.                 logger.debug("Returning handler method [" + handlerMethod + "]");  
  14.             }  
  15.             else {  
  16.                 logger.debug("Did not find handler method for [" + lookupPath + "]");  
  17.             }  
  18.         }  
  19.         return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);  
  20.     }  
在获得HandlerMethod对象之后,通过getHandlerExecutionChain(handler, request)将HandlerMethod对象与Interceptor拦截器封装,成为HandlerExecutionChain的对象。这就是doDispatch方法中mappedHandler引用指向的对象的来源流程。
获得HandlerExecutionChain对象之后,可以通过这个对象获得之前封装进去的HandlerMethod对象。通过getHandler()即可。

[java] view plaincopy
  1. // Determine handler adapter for the current request.  
  2. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());</span>  

而HandlerAdapter接口的具体实现类的对象为真正调用方法,即通过反射调用HandlerMethod对象中封装的某个类的实例所对应的某个方法。

[java] view plaincopy
  1. // Actually invoke the handler.  
  2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());</span>  
返回值为ModelAndView类型的对象,作用就不必多说.而在hanle方法之前和之后有这么两个方法调用:
[java] view plaincopy
  1. mappedHandler.applyPreHandle(processedRequest, response)</span>  
[java] view plaincopy
  1. mappedHandler.applyPostHandle(processedRequest, response, mv);</span>  
作用就是通过执行链中的Interceptor拦截器做拦截处理。功能与Filter相似。


总结如图:





另外应该注意的是,我们若想使用Spring MVC, 就必须有一个类似于SpringapplicationContext.xml那样的配置文件,(默认名为servletName-servlet.xml, 这里的servletName指在web.xml中配置的servletname属性)配置文件,。作用不用多说,与SpringapplicationContext.xml类似,作为IOC容器的核心文件所有bean组件都通过它来创建。也是IOC的核心。



0 0