`
huibin
  • 浏览: 756787 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

Spring源代码解析(四):Spring MVC

阅读更多

下面我们对Spring MVC框架代码进行分析,对于webApplicationContext的相关分析可以参见以前的文档,我们这里着重分析Spring Web MVC框架的实现.我们从分析DispatcherServlet入手:

Java代码 复制代码
  1. //这里是对DispatcherServlet的初始化方法,根据名字我们很方面的 看到对各个Spring MVC主要元素的初始化   
  2. protected   void  initFrameworkServlet()  throws  ServletException, BeansException {   
  3.     initMultipartResolver();   
  4.     initLocaleResolver();   
  5.     initThemeResolver();   
  6.     initHandlerMappings();   
  7.     initHandlerAdapters();   
  8.     initHandlerExceptionResolvers();   
  9.     initRequestToViewNameTranslator();   
  10.     initViewResolvers();   
  11. }  
    //这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个Spring MVC主要元素的初始化
    protected void initFrameworkServlet() throws ServletException, BeansException {
        initMultipartResolver();
        initLocaleResolver();
        initThemeResolver();
        initHandlerMappings();
        initHandlerAdapters();
        initHandlerExceptionResolvers();
        initRequestToViewNameTranslator();
        initViewResolvers();
    }


看到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情 况下进行的,也就意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把 DispatcherServlet的 load-on-startup的属性配置为2的原因。
对于具体的初始化过程,很容易理解,我们拿 initHandlerMappings()来看看:

Java代码 复制代码
  1. private   void  initHandlerMappings()  throws  BeansException {   
  2.      if  ( this .detectAllHandlerMappings) {   
  3.           // 这里找到所有在上下文中定义的 HandlerMapping,同时把他们排序   
  4.           // 因为在同一个上下文中可以有不止一个 handlerMapping,所以我们把他们都载入到一个链里进行维护和管理   
  5.         Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(   
  6.                 getWebApplicationContext(), HandlerMapping. class true false );   
  7.          if  (!matchingBeans.isEmpty()) {   
  8.              this .handlerMappings =  new  ArrayList(matchingBeans.values());   
  9.              // 这里通过order属性来对 handlerMapping来在list中排序   
  10.             Collections.sort( this .handlerMappings,  new  OrderComparator());   
  11.         }   
  12.     }   
  13.      else  {   
  14.          try  {   
  15.             Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping. class );   
  16.              this .handlerMappings = Collections.singletonList(hm);   
  17.         }   
  18.          catch  (NoSuchBeanDefinitionException ex) {   
  19.              // Ignore, we'll add a default HandlerMapping later.   
  20.         }   
  21.     }   
  22.   
  23.      //如果在上下文中没有定义的话,那么我们使用默认的 BeanNameUrlHandlerMapping   
  24.      if  ( this .handlerMappings ==  null ) {   
  25.          this .handlerMappings = getDefaultStrategies(HandlerMapping. class );   
  26.     ........   
  27.     }   
  28. }  
    private void initHandlerMappings() throws BeansException {
        if (this.detectAllHandlerMappings) {
             // 这里找到所有在上下文中定义的HandlerMapping,同时把他们排序
             // 因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理
            Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                    getWebApplicationContext(), HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                // 这里通过order属性来对handlerMapping来在list中排序
                Collections.sort(this.handlerMappings, new OrderComparator());
            }
        }
        else {
            try {
                Object hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        //如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(HandlerMapping.class);
        ........
        }
    }


怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。 DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个 handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到 Spring Controller的映射,比如SimpleUrl
HandlerMaaping中就定义了一个map来持有这一系列的映射关系。
DisptcherServlet 通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那 样,HandlerMapping只是一个借口:

Java代码 复制代码
  1. public   interface  HandlerMapping {   
  2.    public   static   final  String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE =   
  3.                     Conventions.getQualifiedAttributeName(HandlerMapping. class "pathWithinHandlerMapping" );   
  4.        //实际上维护一个 HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器   
  5.     HandlerExecutionChain getHandler(HttpServletRequest request)  throws  Exception;   
  6. }  
public interface HandlerMapping {
  public static final String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE =
                    Conventions.getQualifiedAttributeName(HandlerMapping.class, "pathWithinHandlerMapping");
      //实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}


他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就 像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller:

Java代码 复制代码
  1. public   class  HandlerExecutionChain {   
  2.   
  3.      private  Object handler;   
  4.   
  5.      private  HandlerInterceptor[] interceptors;   
  6.       
  7.     ........   
  8. }  
public class HandlerExecutionChain {

    private Object handler;

    private HandlerInterceptor[] interceptors;
   
    ........
}


而这些Handler和Interceptor需要我们定义HandlerMapping的时候配置好,比如对具体的 SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册Handler和Interceptor,自己维护一个放映映射 的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。这个注册的过程在IOC容器初始化 SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价 的,下面是具体的注册过程:

Java代码 复制代码
  1. protected   void  registerHandlers(Map urlMap)  throws  BeansException {   
  2.      if  (urlMap.isEmpty()) {   
  3.         logger.warn( "Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping" );   
  4.     }   
  5.      else  {   
  6.          //这里迭代在 SimpleUrlHandlerMapping中定义的所有映射元素   
  7.         Iterator it = urlMap.keySet().iterator();   
  8.          while  (it.hasNext()) {   
  9.              //这里取得配置的url   
  10.             String url = (String) it.next();   
  11.              //这里根据url在bean定义中取得对应 的handler   
  12.             Object handler = urlMap.get(url);   
  13.              // Prepend with slash if not already present.   
  14.              if  (!url.startsWith( "/" )) {   
  15.                 url =  "/"  + url;   
  16.             }   
  17.              //这里调用 AbstractHandlerMapping中的注册过程   
  18.             registerHandler(url, handler);   
  19.         }   
  20.     }   
  21. }  
    protected void registerHandlers(Map urlMap) throws BeansException {
        if (urlMap.isEmpty()) {
            logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
        }
        else {
            //这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素
            Iterator it = urlMap.keySet().iterator();
            while (it.hasNext()) {
                //这里取得配置的url
                String url = (String) it.next();
                //这里根据url在bean定义中取得对应的handler
                Object handler = urlMap.get(url);
                // Prepend with slash if not already present.
                if (!url.startsWith("/")) {
                    url = "/" + url;
                }
                //这里调用AbstractHandlerMapping中的注册过程
                registerHandler(url, handler);
            }
        }
    }


在AbstractMappingHandler中的注册代码:

Java代码 复制代码
  1. protected   void  registerHandler(String urlPath, Object handler)  throws  BeansException, IllegalStateException {   
  2.      //试图从handlerMap中取handler,看看是否 已经存在同样的Url映射关系   
  3.     Object mappedHandler =  this .handlerMap.get(urlPath);   
  4.      if  (mappedHandler !=  null ) {   
  5.     ........   
  6.     }   
  7.   
  8.      //如果是直接用bean名做映射那就直接从容器中取 handler   
  9.      if  (! this .lazyInitHandlers && handler  instanceof  String) {   
  10.         String handlerName = (String) handler;   
  11.          if  (getApplicationContext().isSingleton(handlerName)) {   
  12.             handler = getApplicationContext().getBean(handlerName);   
  13.         }   
  14.     }   
  15.      //或者使用默认的handler.   
  16.      if  (urlPath.equals( "/*" )) {   
  17.         setDefaultHandler(handler);   
  18.     }   
  19.      else  {   
  20.     //把url和handler的对应关系放到 handlerMap中去   
  21.          this .handlerMap.put(urlPath, handler);   
  22.         ........   
  23.     }   
  24. }  
    protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
        //试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系
        Object mappedHandler = this.handlerMap.get(urlPath);
        if (mappedHandler != null) {
        ........
        }

        //如果是直接用bean名做映射那就直接从容器中取handler
        if (!this.lazyInitHandlers && handler instanceof String) {
            String handlerName = (String) handler;
            if (getApplicationContext().isSingleton(handlerName)) {
                handler = getApplicationContext().getBean(handlerName);
            }
        }
        //或者使用默认的handler.
        if (urlPath.equals("/*")) {
            setDefaultHandler(handler);
        }
        else {
       //把url和handler的对应关系放到handlerMap中去
            this.handlerMap.put(urlPath, handler);
            ........
        }
    }


handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:

Java代码 复制代码
  1. private   final  Map handlerMap =  new  HashMap();  
    private final Map handlerMap = new HashMap();


而SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初 始化的时候就得到的映射表来生成DispatcherServlet需要的执行链

Java代码 复制代码
  1. public   final  HandlerExecutionChain getHandler(HttpServletRequest request)  throws  Exception {   
  2.      //这里根据request中的参数得到其对应的 handler,具体处理在AbstractUrlHandlerMapping中   
  3.     Object handler = getHandlerInternal(request);   
  4.      //如果找不到对应的,就使用缺省的handler   
  5.      if  (handler ==  null ) {   
  6.         handler =  this .defaultHandler;   
  7.     }   
  8.      //如果缺省的也没有,那就没办法了   
  9.      if  (handler ==  null ) {   
  10.          return   null ;   
  11.     }   
  12.      // 如果handler不是一个具体的handler,那我 们还要到上下文中取   
  13.      if  (handler  instanceof  String) {   
  14.         String handlerName = (String) handler;   
  15.         handler = getApplicationContext().getBean(handlerName);   
  16.     }   
  17.      //生成一个HandlerExecutionChain,其 中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一 个拦截器组。   
  18.      return   new  HandlerExecutionChain(handler,  this .adaptedInterceptors);   
  19. }  
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中
        Object handler = getHandlerInternal(request);
        //如果找不到对应的,就使用缺省的handler
        if (handler == null) {
            handler = this.defaultHandler;
        }
        //如果缺省的也没有,那就没办法了
        if (handler == null) {
            return null;
        }
        // 如果handler不是一个具体的handler,那我们还要到上下文中取
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。
        return new HandlerExecutionChain(handler, this.adaptedInterceptors);
    }


我们看看具体的handler查找过程:

Java代码 复制代码
  1. protected  Object getHandlerInternal(HttpServletRequest request)  throws  Exception {   
  2.      //这里的HTTP Request传进来的参数进行分析,得 到具体的路径信息。   
  3.     String lookupPath =  this .urlPathHelper.getLookupPathForRequest(request);   
  4.     ....... //下面是根据请求信息的查找   
  5.      return  lookupHandler(lookupPath, request);   
  6. }   
  7.   
  8. protected  Object lookupHandler(String urlPath, HttpServletRequest request) {   
  9.      // 如果能够直接能在 SimpleUrlHandlerMapping的映射表中找到,那最好。   
  10.     Object handler =  this .handlerMap.get(urlPath);   
  11.      if  (handler ==  null ) {   
  12.          // 这里使用模式来对map中的所有handler 进行匹配,调用了Jre中的Matcher类来完成匹配处理。   
  13.         String bestPathMatch =  null ;   
  14.          for  (Iterator it =  this .handlerMap.keySet().iterator(); it.hasNext();) {   
  15.             String registeredPath = (String) it.next();   
  16.              if  ( this .pathMatcher.match(registeredPath, urlPath) &&   
  17.                             (bestPathMatch ==  null  || bestPathMatch.length() <= registeredPath.length())) {   
  18.                  //这里根据匹配路径找到最象的一个   
  19.                 handler =  this .handlerMap.get(registeredPath);   
  20.                 bestPathMatch = registeredPath;   
  21.             }   
  22.         }   
  23.   
  24.          if  (handler !=  null ) {   
  25.             exposePathWithinMapping( this .pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request);   
  26.         }   
  27.     }   
  28.      else  {   
  29.         exposePathWithinMapping(urlPath, request);   
  30.     }   
  31.      //   
  32.      return  handler;   
  33. }  
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        //这里的HTTP Request传进来的参数进行分析,得到具体的路径信息。
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        .......//下面是根据请求信息的查找
        return lookupHandler(lookupPath, request);
    }

    protected Object lookupHandler(String urlPath, HttpServletRequest request) {
        // 如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。
        Object handler = this.handlerMap.get(urlPath);
        if (handler == null) {
            // 这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。
            String bestPathMatch = null;
            for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
                String registeredPath = (String) it.next();
                if (this.pathMatcher.match(registeredPath, urlPath) &&
                                (bestPathMatch == null || bestPathMatch.length() <= registeredPath.length())) {
                    //这里根据匹配路径找到最象的一个
                    handler = this.handlerMap.get(registeredPath);
                    bestPathMatch = registeredPath;
                }
            }

            if (handler != null) {
                exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch, urlPath), request);
            }
        }
        else {
            exposePathWithinMapping(urlPath, request);
        }
        //
        return handler;
    }


我们可以看到,总是在handlerMap这个HashMap中找,当然如果直接找到最好,如果找不到,就看看是不是能通过Match Pattern的模式找,我们一定还记得在配置HnaderMapping的时候是可以通过ANT语法进行配置的,其中的处理就在这里。
这样可 以清楚地看到整个HandlerMapping的初始化过程 - 同时,我们也看到了一个具体的handler映射是怎样被存储和查找的 - 这里生成一个ExecutionChain来储存我们找到的handler和在定义bean的时候定义的Interceptors.
让我们回到 DispatcherServlet,初始化完成以后,实际的对web请求是在doService()方法中处理的,我们知道 DispatcherServlet只是一个普通的Servlet:

Java代码 复制代码
  1. protected   void  doService(HttpServletRequest request, HttpServletResponse response)  throws  Exception {   
  2.     .......   
  3.      //这里把属性信息进行保存   
  4.     Map attributesSnapshot =  null ;   
  5.      if  (WebUtils.isIncludeRequest(request)) {   
  6.         logger.debug( "Taking snapshot of request attributes before include" );   
  7.         attributesSnapshot =  new  HashMap();   
  8.         Enumeration attrNames = request.getAttributeNames();   
  9.          while  (attrNames.hasMoreElements()) {   
  10.             String attrName = (String) attrNames.nextElement();   
  11.              if  ( this .cleanupAfterInclude || attrName.startsWith(DispatcherServlet. class .getName())) {   
  12.                 attributesSnapshot.put(attrName, request.getAttribute(attrName));   
  13.             }   
  14.         }   
  15.     }   
  16.   
  17.      // Make framework objects available to handlers and view objects.   
  18.     request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());   
  19.     request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE,  this .localeResolver);   
  20.     request.setAttribute(THEME_RESOLVER_ATTRIBUTE,  this .themeResolver);   
  21.     request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());   
  22.   
  23.      try  {   
  24.           //这里使实际的处理入口   
  25.         doDispatch(request, response);   
  26.     }   
  27.      finally  {   
  28.          // Restore the original attribute snapshot, in case of an include.   
  29.          if  (attributesSnapshot !=  null ) {   
  30.             restoreAttributesAfterInclude(request, attributesSnapshot);   
  31.         }   
  32.     }   
  33. }  
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        .......
        //这里把属性信息进行保存
        Map attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            logger.debug("Taking snapshot of request attributes before include");
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith(DispatcherServlet.class.getName())) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        try {
             //这里使实际的处理入口
            doDispatch(request, response);
        }
        finally {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }


我们看到,对于请求的处理实际上是让doDispatch()来完成的 - 这个方法很长,但是过程很简单明了:

Java代码 复制代码
  1. protected   void  doDispatch( final  HttpServletRequest request, HttpServletResponse response)  throws  Exception {   
  2.     HttpServletRequest processedRequest = request;   
  3.      //这是从handlerMapping中得到的执行链   
  4.     HandlerExecutionChain mappedHandler =  null ;   
  5.      int  interceptorIndex = - 1 ;   
  6.       
  7.     ........   
  8.      try  {   
  9.          //我们熟悉的ModelAndView开始出现了。   
  10.         ModelAndView mv =  null ;   
  11.          try  {   
  12.             processedRequest = checkMultipart(request);   
  13.   
  14.              // 这是我们得到handler的过程   
  15.             mappedHandler = getHandler(processedRequest,  false );   
  16.              if  (mappedHandler ==  null  || mappedHandler.getHandler() ==  null ) {   
  17.                 noHandlerFound(processedRequest, response);   
  18.                  return ;   
  19.             }   
  20.   
  21.              // 这里取出执行链中的 Interceptor进行前处理   
  22.              if  (mappedHandler.getInterceptors() !=  null ) {   
  23.                  for  ( int  i =  0 ; i < mappedHandler.getInterceptors().length; i++) {   
  24.                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];   
  25.                      if  (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {   
  26.                         triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response,  null );   
  27.                          return ;   
  28.                     }   
  29.                     interceptorIndex = i;   
  30.                 }   
  31.             }   
  32.   
  33.              //在执行handler之前,用 HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。   
  34.             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());   
  35.             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());   
  36.   
  37.              // 这里取出执行链中的 Interceptor进行后处理   
  38.              if  (mappedHandler.getInterceptors() !=  null ) {   
  39.                  for  ( int  i = mappedHandler.getInterceptors().length -  1 ; i >=  0 ; i--) {   
  40.                     HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];   
  41.                     interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);   
  42.                 }   
  43.             }   
  44.         }   
  45.           
  46.         ........   
  47.   
  48.          // Did the handler return a view to render?   
  49.          //这里对视图生成进行处理   
  50.          if  (mv !=  null  && !mv.wasCleared()) {   
  51.             render(mv, processedRequest, response);   
  52.         }   
  53.         .......   
  54. }  
    protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        //这是从handlerMapping中得到的执行链
        HandlerExecutionChain mappedHandler = null;
        int interceptorIndex = -1;
       
        ........
        try {
            //我们熟悉的ModelAndView开始出现了。
            ModelAndView mv = null;
            try {
                processedRequest = checkMultipart(request);

                // 这是我们得到handler的过程
                mappedHandler = getHandler(processedRequest, false);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 这里取出执行链中的Interceptor进行前处理
                if (mappedHandler.getInterceptors() != null) {
                    for (int i = 0; i < mappedHandler.getInterceptors().length; i++) {
                        HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
                        if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
                            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                            return;
                        }
                        interceptorIndex = i;
                    }
                }

                //在执行handler之前,用HandlerAdapter先检查一下handler的合法性:是不是按Spring的要求编写的。
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                // 这里取出执行链中的Interceptor进行后处理
                if (mappedHandler.getInterceptors() != null) {
                    for (int i = mappedHandler.getInterceptors().length - 1; i >= 0; i--) {
                        HandlerInterceptor interceptor = mappedHandler.getInterceptors()[i];
                        interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
                    }
                }
            }
           
            ........

            // Did the handler return a view to render?
            //这里对视图生成进行处理
            if (mv != null && !mv.wasCleared()) {
                render(mv, processedRequest, response);
            }
            .......
    }


我们很清楚的看到和MVC框架紧密相关的代码,比如如何得到和http请求相对应的执行链,怎样执行执行链和怎样把模型数据展现到视图中 去。
先看怎样取得Command对象,对我们来说就是Handler - 下面是getHandler的代码:

Java代码 复制代码
  1. protected  HandlerExecutionChain getHandler(HttpServletRequest request,  boolean  cache)  throws  Exception {   
  2.    //在ServletContext取得执行链 - 实际上第一次 得到它的时候,我们把它放在ServletContext进行了缓存。   
  3.   HandlerExecutionChain handler =   
  4.             (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);   
  5.      if  (handler !=  null ) {   
  6.          if  (!cache) {   
  7.             request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);   
  8.         }   
  9.          return  handler;   
  10.     }   
  11.      //这里的迭代器迭代的时在 initHandlerMapping中载入的上下文所有的HandlerMapping   
  12.     Iterator it =  this .handlerMappings.iterator();   
  13.      while  (it.hasNext()) {   
  14.         HandlerMapping hm = (HandlerMapping) it.next();   
  15.         .......   
  16.          //这里是实际取得handler的过程,在每个 HandlerMapping中建立的映射表进行检索得到请求对应的handler   
  17.         handler = hm.getHandler(request);   
  18.   
  19.          //然后把handler存到 ServletContext中去进行缓存   
  20.          if  (handler !=  null ) {   
  21.              if  (cache) {   
  22.                 request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);   
  23.             }   
  24.              return  handler;   
  25.         }   
  26.     }   
  27.      return   null ;   
  28. }  
    protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception {
      //在ServletContext取得执行链 - 实际上第一次得到它的时候,我们把它放在ServletContext进行了缓存。
      HandlerExecutionChain handler =
                (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
        if (handler != null) {
            if (!cache) {
                request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
            }
            return handler;
        }
        //这里的迭代器迭代的时在initHandlerMapping中载入的上下文所有的HandlerMapping
        Iterator it = this.handlerMappings.iterator();
        while (it.hasNext()) {
            HandlerMapping hm = (HandlerMapping) it.next();
            .......
            //这里是实际取得handler的过程,在每个HandlerMapping中建立的映射表进行检索得到请求对应的handler
            handler = hm.getHandler(request);

            //然后把handler存到ServletContext中去进行缓存
            if (handler != null) {
                if (cache) {
                    request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler);
                }
                return handler;
            }
        }
        return null;
    }


如果在ServletContext中可以取得handler则直接返回,实际上这个handler是缓冲了上次处理的结果 - 总要有第一次把这个handler放到ServletContext中去:
如果在ServletContext中找不到handler,那就通 过持有的handlerMapping生成一个,我们看到它会迭代当前持有的所有的 handlerMapping,因为可以定义不止一个,他们在定义的时候也可以指定顺序,直到找到第一个,然后返回。先找到一个 handlerMapping,然后通过这个handlerMapping返回一个执行链,里面包含了最终的Handler和我们定义的一连串的 Interceptor。具体的我们可以参考上面的SimpleUrlHandlerMapping的代码分析知道getHandler是怎样得到一个 HandlerExecutionChain的。
得到HandlerExecutionChain以后,我们通过HandlerAdapter 对这个Handler的合法性进行判断:

Java代码 复制代码
  1. protected  HandlerAdapter getHandlerAdapter(Object handler)  throws  ServletException {   
  2.     Iterator it =  this .handlerAdapters.iterator();   
  3.      while  (it.hasNext()) {   
  4.          //同样对持有的所有adapter进行匹配   
  5.         HandlerAdapter ha = (HandlerAdapter) it.next();   
  6.          if  (ha.supports(handler)) {   
  7.              return  ha;   
  8.         }   
  9.     }   
  10.     ........   
  11. }  
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        Iterator it = this.handlerAdapters.iterator();
        while (it.hasNext()) {
            //同样对持有的所有adapter进行匹配
            HandlerAdapter ha = (HandlerAdapter) it.next();
            if (ha.supports(handler)) {
                return ha;
            }
        }
        ........
    }


通过判断,我们知道这个handler是不是一个Controller接口的实现,比如对于具体的HandlerAdapter - SimpleControllerHandlerAdapter:

Java代码 复制代码
  1. public   class  SimpleControllerHandlerAdapter  implements  HandlerAdapter {   
  2.       
  3.      public   boolean  supports(Object handler) {   
  4.          return  (handler  instanceof  Controller);   
  5.     }   
  6.     .......   
  7. }  
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
   
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }
    .......
}


简单的判断一下handler是不是实现了Controller接口。这也体现了一种对配置文件进行验证的机制。
让我们再回到 DispatcherServlet看到代码:

Java代码 复制代码
  1. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());


这个就是对handle的具体调用!相当于Command模式里的Command.execute();理所当然的返回一个 ModelAndView,下面就是一个对View进行处理的过程:

Java代码 复制代码
  1. if  (mv !=  null  && !mv.wasCleared()) {   
  2.     render(mv, processedRequest, response);   
  3. }  
            if (mv != null && !mv.wasCleared()) {
                render(mv, processedRequest, response);
            }


调用的是render方法:

Java代码 复制代码
  1. protected   void  render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)   
  2.           throws  Exception {response.setLocale(locale);   
  3.   
  4.      View view =  null ;   
  5.       //这里把默认的视图放到ModelAndView中去。   
  6.       if  (!mv.hasView()) {   
  7.          mv.setViewName(getDefaultViewName(request));   
  8.      }   
  9.   
  10.       if  (mv.isReference()) {   
  11.           // 这里对视图名字进行解析   
  12.          view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);   
  13.      .......   
  14.      }   
  15.       else  {   
  16.           // 有可能在ModelAndView里已经直接 包含了View对象,那我们就直接使用。   
  17.          view = mv.getView();   
  18.      ........   
  19.      }   
  20.   
  21.       //得到具体的View对象以后,我们用它来生成视图。   
  22.      view.render(mv.getModelInternal(), request, response);   
  23.  }  
   protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response)
            throws Exception {response.setLocale(locale);

        View view = null;
        //这里把默认的视图放到ModelAndView中去。
        if (!mv.hasView()) {
            mv.setViewName(getDefaultViewName(request));
        }

        if (mv.isReference()) {
            // 这里对视图名字进行解析
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
        .......
        }
        else {
            // 有可能在ModelAndView里已经直接包含了View对象,那我们就直接使用。
            view = mv.getView();
        ........
        }

        //得到具体的View对象以后,我们用它来生成视图。
        view.render(mv.getModelInternal(), request, response);
    }


从整个过程我们看到先在ModelAndView中寻找视图的逻辑名,如果找不到那就使用缺省的视图,如果能够找到视图的名字,那就对他进 行解析得到实际的需要使用的视图对象。还有一种可能就是在ModelAndView中已经包含了实际的视图对象,这个视图对象是可以直接使用的。
不 管怎样,得到一个视图对象以后,通过调用视图对象的render来完成数据的显示过程,我们可以看看具体的JstlView是怎样实现的,我们在 JstlView的抽象父类 AbstractView中找到render方法:

Java代码 复制代码
  1. public   void  render(Map model, HttpServletRequest request, HttpServletResponse response)  throws  Exception {   
  2.     ......   
  3.      // 这里把所有的相关信息都收集到一个Map里   
  4.     Map mergedModel =  new  HashMap( this
    分享到:
    评论
    2 楼 kensunhu 2012-04-13  
    整个主线是串起来了,MVC: request=>mapping controller=>handle request=>render view=>response. 同一份代码为什么copy两次呢?加深记忆?
    1 楼 waainli 2012-03-26  
    这个源代码是Spring什么版本的啊?写的挺好的。

相关推荐

    Spring源代码解析.rar

    Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring源代码解析6:Spring声明式事务处理 .doc Spring源代码解析7:Spring AOP中对拦截器调用的实现 .doc Spring源代码解析8:...

    Spring 源代码解析

    Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动...

    Spring源代码解析

    Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):...

    springyuanmaaping.zip

    Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动...

    Spring源代码解析(四):Spring_MVC.doc

    在Spring源代码解析的第四部分中,我们将重点关注DispatcherServlet的初始化过程,它是Spring MVC的核心组件。 DispatcherServlet是一个特殊的Servlet,它负责接收HTTP请求,并根据请求映射到相应的处理器...

    Spring源码学习文档,绝对值得好好研究~~

    Spring源代码解析(四):Spring MVC.doc Spring源代码解析(五):Spring AOP获取Proxy.doc Spring源代码解析(六):Spring声明式事务处理.doc Spring源代码解析(七):Spring AOP中对拦截器调用的实现.doc Spring源...

    spring mvc源代码

    spring mvc4.1.4 源代码 spring mvc4.1.4 源代码spring mvc4.1.4 源代码spring mvc4.1.4 源代码spring mvc4.1.4 源代码

    springmvc深入解析.pdf

    Spring MVC深入解析 Spring MVC是一个基于模型-视图-控制器(MVC)模式的Web应用程序框架,是Spring Framework的一部分。它提供了一个灵活的方式来构建Web应用程序,使得开发者可以轻松地创建复杂的Web应用程序。 ...

    spring 源代码解析.zip

    《Spring源代码解析》 Spring框架作为Java领域最流行的开源框架之一,它的设计思想和实现方式一直是广大开发者关注的焦点。深入理解Spring的源代码,能够帮助我们更好地掌握其工作原理,提高我们的开发效率和代码...

    看透Spring MVC源代码分析与实践

    《看透Spring MVC源代码分析与实践》这本书深入剖析了Spring MVC这一强大的Web应用程序开发框架。Spring MVC作为Spring框架的一部分,被广泛应用于企业级Java应用中,它为开发者提供了构建可扩展、模块化且易于维护...

    《看透Spring MVC:源代码分析与实践》epub

    书名:《看透Spring MVC:源代码分析与实践》 作者:韩路彪 Spring MVC相关的源码分析

    看透Spring MVC:源代码分析与实践.pdf

    看透Spring MVC:源代码分析与实践

    Spring 源代码解析.rar

    这个“Spring源代码解析”压缩包文件很可能是对Spring框架内部实现原理的详细分析,帮助开发者深入理解其工作机制。 在Spring框架中,依赖注入是核心概念之一,它允许开发者在运行时通过容器来管理对象的创建和依赖...

    spring-webmvc-5.0.8.RELEASE-API文档-中文版.zip

    赠送源代码:spring-webmvc-5.0.8.RELEASE-sources.jar; 赠送Maven依赖信息文件:spring-webmvc-5.0.8.RELEASE.pom; 包含翻译后的API文档:spring-webmvc-5.0.8.RELEASE-javadoc-API文档-中文(简体)版.zip; Maven...

    源码: 看透Spring MVC:源代码分析与实践

    《看透Spring MVC:源代码分析与实践》是一本深入探讨Spring MVC框架核心机制的书籍。通过对源代码的解析,读者可以深入了解这个广泛使用的Java Web开发框架的工作原理,从而更好地运用和优化自己的项目。该书提供了...

    《Java EE企业级应用开发教程Spring+Spring MVC+MyBatis》_源代码.zip

    《Java EE企业级应用开发教程Spring+Spring MVC+MyBatis》是一本深入探讨Java企业级应用程序开发的书籍,源代码包含多个章节的实例,旨在帮助读者理解和掌握使用Spring、Spring MVC和MyBatis框架进行实际开发的关键...

    【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip

    这份【面试资料】-(机构内训资料)看透Spring MVC源代码分析与实践.zip文件很可能是为了帮助求职者准备相关面试问题而设计的,包含了对Spring MVC工作原理、关键组件和源码解读的详尽解析。 1. **Spring MVC基本...

Global site tag (gtag.js) - Google Analytics