文档章节

Spring 源码分析(四) ——MVC(六)M 与 C 的实现

水门-kay
 水门-kay
发布于 2016/04/02 19:20
字数 2896
阅读 1029
收藏 6

MVC 处理 HTTP 分发请求

        HandlerMapping 配置与设计

        在初始化完成时,在上下文环境中已定义的所有 HandlerMapping 都已经被加载了,这些加载的 handlerMapping 被放在一个 List 中并被排序,存储着 HTTP 请求对应的映射数据。这个 List 中的每一个元素都对应着一个具体 handlerMapping 的配置,一般每一个 handlerMapping 可以持有一系列从 URL 请求到 Controller 的映射,而 Spring MVC 提供了一系列的 HandlerMapping 实现。如下:

        通过这些在 HandlerMapping 中定义的映射关系,即这些 URL 请求和控制器的对应关系,使 Spring MVC 应用可以根据 HTTP 请求确定一个对应的 Controller。具体来说,这些映射关系是通过接口类 HandlerMapping 来封装的,在 HandlerMapping 接口中定义了一个 getHandler 方法,通过这个方法,可以获得与 HTTP 请求对应的 HandlerExecutionChain,而这个 HandlerExecutionChain,封装了具体的 Controller 对象:

public interface HandlerMapping {
   String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
   String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
   String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
   String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
   String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
   String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
   // 调用 getHandler 实际上返回的是一个 HandlerExecutionChain ,这是典型的 Command 的模式的使用,这个 HandlerExecutionChain 
   // 不但持有 handler 本身,还包括了处理这个 HTTP 请求相关的拦截器
   HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

        HandlerExecutionChain 看起来比较简洁,它持有一个 Interceptor 链和一个 handler 对象,这个 handler 对象实际上就是 HTTP 请求对应的 Controller,在持有这个 handler 对象的同时,还在 HandlerExecutionChain 中设置了一个拦截器链,通过这个拦截器链中的拦截器,可以为 handler 对象提供功能的增强。要完成这些工作,需要对拦截器链和 handler 都进行配置,这些配置都是在 HandlerExecutionChain 的初始化函数中完成的。为了维护这个拦截器链和 handler,handlerExecutionChain 还提供了一系列与拦截器链维护相关的一些操作,比如可以为拦截器链增加拦截器的 addInterceptor 方法等。

public class HandlerExecutionChain {

   private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

   private final Object handler;

   private HandlerInterceptor[] interceptors;

   private List<HandlerInterceptor> interceptorList;

   private int interceptorIndex = -1;

   public HandlerExecutionChain(Object handler) {
      this(handler, (HandlerInterceptor[]) null);
   }

   public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
      if (handler instanceof HandlerExecutionChain) {
         HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
         this.handler = originalChain.getHandler();
         this.interceptorList = new ArrayList<HandlerInterceptor>();
         CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
         CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
      }
      else {
         this.handler = handler;
         this.interceptors = interceptors;
      }
   }

   public Object getHandler() {
      return this.handler;
   }

   public void addInterceptor(HandlerInterceptor interceptor) {
      initInterceptorList().add(interceptor);
   }

   public void addInterceptors(HandlerInterceptor... interceptors) {
      if (!ObjectUtils.isEmpty(interceptors)) {
         initInterceptorList().addAll(Arrays.asList(interceptors));
      }
   }

   private List<HandlerInterceptor> initInterceptorList() {
      if (this.interceptorList == null) {
         this.interceptorList = new ArrayList<HandlerInterceptor>();
         if (this.interceptors != null) {
            // An interceptor array specified through the constructor
            this.interceptorList.addAll(Arrays.asList(this.interceptors));
         }
      }
      this.interceptors = null;
      return this.interceptorList;
   }

   public HandlerInterceptor[] getInterceptors() {
      if (this.interceptors == null && this.interceptorList != null) {
         this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
      }
      return this.interceptors;
   }

   boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
               triggerAfterCompletion(request, response, null);
               return false;
            }
            this.interceptorIndex = i;
         }
      }
      return true;
   }

   void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
         }
      }
   }

   void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
         throws Exception {

      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = this.interceptorIndex; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            try {
               interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
               logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
         }
      }
   }

   void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
      HandlerInterceptor[] interceptors = getInterceptors();
      if (!ObjectUtils.isEmpty(interceptors)) {
         for (int i = interceptors.length - 1; i >= 0; i--) {
            if (interceptors[i] instanceof AsyncHandlerInterceptor) {
               try {
                  AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
                  asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
               }
               catch (Throwable ex) {
                  logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
               }
            }
         }
      }
   }

   @Override
   public String toString() {
      if (this.handler == null) {
         return "HandlerExecutionChain with no handler";
      }
      StringBuilder sb = new StringBuilder();
      sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]");
      if (!CollectionUtils.isEmpty(this.interceptorList)) {
         sb.append(" and ").append(this.interceptorList.size()).append(" interceptor");
         if (this.interceptorList.size() > 1) {
            sb.append("s");
         }
      }
      return sb.toString();
   }
}

        下面我们以 SimpleUrlHandlerMapping 说明在实际中是如何应用的,SimpleUrlHandlerMapping 定义了一个 Map 变量(自己定义一个 Map 主要有两个作用,第一是方便配置,第二是可以在注册前做一些预处理,如确保所以 url 都以”/“开头),将所有的 url 和 Handler 的对应关系放在里面,最后注册到父类的 Map 中。

SimpleUrlHandlerMapping.java 

public void initApplicationContext() throws BeansException {
    super.initApplicationContext();
    registerHandlers(this.urlMap);
}

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
    if (urlMap.isEmpty()) {
        logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    }
    else {
        for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
            String url = entry.getKey();
            Object handler = entry.getValue();
            // Prepend with slash if not already present.
            if (!url.startsWith("/")) {
               url = "/" + url;
            }
            // Remove whitespace from handler bean name.
            if (handler instanceof String) {
               handler = ((String) handler).trim();
            }
            registerHandler(url, handler);
        }
    }
}

        AbstractUrlHandlerMapping 对 handler 的注册。

AbstractUrlHandlerMapping.java

protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
   Assert.notNull(urlPath, "URL path must not be null");
   Assert.notNull(handler, "Handler object must not be null");
   Object resolvedHandler = handler;

   // Eagerly resolve handler if referencing singleton via name.
   if (!this.lazyInitHandlers && handler instanceof String) {
      String handlerName = (String) handler;
      if (getApplicationContext().isSingleton(handlerName)) {
         resolvedHandler = getApplicationContext().getBean(handlerName);
      }
   }

   Object mappedHandler = this.handlerMap.get(urlPath);
   if (mappedHandler != null) {
      if (mappedHandler != resolvedHandler) {
         throw new IllegalStateException(
               "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
               "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
      }
   }
   else {
      if (urlPath.equals("/")) {
         if (logger.isInfoEnabled()) {
            logger.info("Root mapping to " + getHandlerDescription(handler));
         }
         setRootHandler(resolvedHandler);
      }
      else if (urlPath.equals("/*")) {
         if (logger.isInfoEnabled()) {
            logger.info("Default mapping to " + getHandlerDescription(handler));
         }
         setDefaultHandler(resolvedHandler);
      }
      else {
         this.handlerMap.put(urlPath, resolvedHandler);
         if (logger.isInfoEnabled()) {
            logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
         }
      }
   }
}


        HandlerMapping 完成请求和映射处理

        在各种准备工作完成后,就是使用 HandlerMapping 来完成请求的映射处理了,而具体执行过程是在 AbstactHandlerMapping 中的 getHandler 来完成的。

AbstactHandlerMapping.java 

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   Object handler = getHandlerInternal(request);
   // 使用默认的 Handler,也就是"/"对应的 handler
   if (handler == null) {
      handler = getDefaultHandler();
   }
   // 这里通过名称取出对应的 Handler Bean
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }

   // 这里把 Handler 封装到 HandlerExecutionChain 中并加上拦截器
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
      if (interceptor instanceof MappedInterceptor) {
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
            chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
      }
      else {
         chain.addInterceptor(interceptor);
      }
   }
   return chain;
}

        在取得 handler 的具体过程在 getHandlerInternal 方法中实现。这个方法接受 HTTP 请求作为参数,它的实现在 AbstractUrlHandlerMapping 中,这个实现过程包括从 HTTP 请求中得到 URL ,并根据 URL 到 urlMapping 中获取 handler。

AbstractUrlHandlerMapping .java

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
   // 从request 中得到请求的 URL 路径
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   // 将得到的 URL 路径与 Handler 进行匹配
   Object handler = lookupHandler(lookupPath, request);
   if (handler == null) {
      // We need to care for the default handler directly, since we need to
      // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
      Object rawHandler = null;
      if ("/".equals(lookupPath)) {
         rawHandler = getRootHandler();
      }
      if (rawHandler == null) {
         rawHandler = getDefaultHandler();
      }
      if (rawHandler != null) {
         // Bean name or resolved handler?
         if (rawHandler instanceof String) {
            String handlerName = (String) rawHandler;
            rawHandler = getApplicationContext().getBean(handlerName);
         }
         validateHandler(rawHandler, request);
         handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
      }
   }
   if (handler != null && logger.isDebugEnabled()) {
      logger.debug("Mapping [" + lookupPath + "] to " + handler);
   }
   else if (handler == null && logger.isTraceEnabled()) {
      logger.trace("No handler mapping found for [" + lookupPath + "]");
   }
   return handler;
}

// lookupHandler 根据 URL 路径启动在 HandlerMap 中对 handler 的检索,并最终返回 handler 对象
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
   // Direct match?
   Object handler = this.handlerMap.get(urlPath);
   if (handler != null) {
      // Bean name or resolved handler?
      if (handler instanceof String) {
         String handlerName = (String) handler;
         handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      return buildPathExposingHandler(handler, urlPath, urlPath, null);
   }
   // Pattern match?
   List<String> matchingPatterns = new ArrayList<String>();
   for (String registeredPattern : this.handlerMap.keySet()) {
      if (getPathMatcher().match(registeredPattern, urlPath)) {
         matchingPatterns.add(registeredPattern);
      }
      else if (useTrailingSlashMatch()) {
         if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
            matchingPatterns.add(registeredPattern +"/");
         }
      }
   }
   String bestPatternMatch = null;
   Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
   if (!matchingPatterns.isEmpty()) {
      Collections.sort(matchingPatterns, patternComparator);
      if (logger.isDebugEnabled()) {
         logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
      }
      bestPatternMatch = matchingPatterns.get(0);
   }
   if (bestPatternMatch != null) {
      handler = this.handlerMap.get(bestPatternMatch);
      if (handler == null) {
         Assert.isTrue(bestPatternMatch.endsWith("/"));
         handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
      }
      // Bean name or resolved handler?
      if (handler instanceof String) {
         String handlerName = (String) handler;
         handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

      // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
      // for all of them
      Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
      for (String matchingPattern : matchingPatterns) {
         if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
            Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
            Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
            uriTemplateVariables.putAll(decodedVars);
         }
      }
      if (logger.isDebugEnabled()) {
         logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
      }
      return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
   }
   // No handler found...
   return null;
}

       至此,HTTP 请求的解析和匹配 Handler 过程就全部完成了,剩下的就是 HTTP 请求的分发处理了。


        Spring MVC 对 HTTP 请求的分发处理

        让我们重回到 DispatcherServlet,毫无疑问,它是 Spring MVC 中非常重要的一个类,他不仅仅建立了自己的持有 Ioc 容器,还肩负请求分布处理的任务。而 HTTP 的请求发布处理是在 doService 方法中完成的。

DispatcherServlet.java

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
      logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
            " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
   }

   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

   // 对 HTTP 请求参数进行处理
   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());

   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
   if (inputFlashMap != null) {
      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   }
   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

   try {
      // 这里是 doDispatch 的分发请求的人口
      doDispatch(request, response);
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         // Restore the original attribute snapshot, in case of an include.
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
   }
}

        对于请求的实际处理是由 doDispatch() 来完成的,这个方法很长,但过程简单明了。这个 doDispatch 方法是 DispatcherServlet 完成 Dispatcher 的主要方法,包括准备 ModelAndView,调用 getHandler 来响应 HTTP 请求,然后通过执行 Handler 的处理来得到返回的 ModelAndView 结果,最后把这个 ModelAndView 对象交给相应的视图对象去呈现。这里是 MVC 模式的核心地区: 

DispatcherServlet.java

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

   // 这里为视图准备好一个 ModelAndView,这个 ModelAndView 持有 handler 处理请求的结果
   try {
      ModelAndView mv = null;
      Exception dispatchException = null;

      try {
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // 根据请求得到对应的 handler,handler 的注册以及 getHandler 的实现
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // 调用 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;
            }
         }

         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }

         applyDefaultViewName(processedRequest, mv);
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
   }
   catch (Error err) {
      triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
         }
      }
   }
}

        这里是与 MVC 框架最紧密相关的代码,得到 HTTP 请求对应的 HandlerExecutionChain ,执行 handler 并把模型数据展现到视图中去。

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      if (logger.isTraceEnabled()) {
         logger.trace(
               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
      }
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}

        其实,这个方法执行结束,MVC 框架中的 Controller 和 定义的一个拦截器链已经包含在其中了。然后,需要执行的就是返回适配的结果了。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   // 对持有的所有 adapter 进行匹配
   for (HandlerAdapter ha : this.handlerAdapters) {
      if (logger.isTraceEnabled()) {
         logger.trace("Testing handler adapter [" + ha + "]");
      }
      if (ha.supports(handler)) {
         return ha;
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

        这里的 handler 是不是 Controller 接口的实现,可以通过 HandlerAdapter 来了解这个适配的过程。而具体的适配过程,我们以 SimpleControllerHandlerAdapter 的实现来说明。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

   // 判断将要调用的 handler 是不是 Controller.
   @Override
   public boolean supports(Object handler) {
      return (handler instanceof Controller);
   }

   @Override
   public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {

      return ((Controller) handler).handleRequest(request, response);
   }

   @Override
   public long getLastModified(HttpServletRequest request, Object handler) {
      if (handler instanceof LastModified) {
         return ((LastModified) handler).getLastModified(request);
      }
      return -1L;
   }

}

        得到 handler 对象,然后调用 handler 对象中的 HTTP 进行动作的响应。而具体的业务逻辑则被封装在 handler 中,由这些逻辑对 HTTP 请求进行相应的处理,从而生成所需要的数据,并把这些数据封装到 ModelAndView 对象中。最后,通过 handler 的 handlerRequest 方法触发完成,然后交给 MVC 的 View 部分处理。至此,Spring MVC 的主要逻辑就完成了。前面已经,分析了,MVC 的 C 和 M 部分。下面就是 View 部分的分析了。



——水门(2016年4月写于杭州)

© 著作权归作者所有

水门-kay
粉丝 460
博文 19
码字总数 59660
作品 0
杭州
后端工程师
私信 提问
Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密...

小致Daddy
2018/08/03
21.9K
1
Spring 源码分析(四) ——MVC(七)视图呈现

DispatcherServlet 视图设计 前面分析了 Spring MVC 中的 M(Model)和 C(Controller)相关的实现,其中的 M 大致对应 ModelAndView 的生成,而 C 大致对应 DispatcherServlet 和与用户业务...

水门-kay
2016/04/02
794
0
springmvc源码解析合集

更多精彩源码解析文章请关注”天河聊架构“微信公众号。 springmvc源码解析之组件介绍 springmvc源码解析之配置加载SpringServletContainerInitializer springmvc源码解析之配置加载Context...

天河2018
03/27
212
0
史上最简单的 Spring MVC 教程

1 前言   spring MVC 属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块,而 Spring MVC 就是其中最优秀的 MVC ...

qq_35246620
2017/01/25
0
0
springMVC笔记系列(19)——控制器实现详解(上)

本文我们在前文基础上引入一个例子,边做边聊控制器。 我们想实现一个课程查询的功能。 首先大脑应该条件反射——如何定义MVC。 M:课程(包含章节)——Course(包含Chapter) V:课程页面—...

HappyBKs
2016/06/19
552
1

没有更多内容

加载失败,请刷新页面

加载更多

3_数组

3_数组

行者终成事
今天
7
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0
使用logstash同步MySQL数据到ES

概述   在生成业务常有将MySQL数据同步到ES的需求,如果需要很高的定制化,往往需要开发同步程序用于处理数据。但没有特殊业务需求,官方提供的logstash就很有优势了。   在使用logstas...

zxiaofan666
今天
10
0
X-MSG-IM-分布式信令跟踪能力

经过一周多的鏖战, X-MSG-IM的分布式信令跟踪能力已基本具备, 特点是: 实时. 只有要RX/TX就会实时产生信令跟踪事件, 先入kafka, 再入influxdb待查. 同时提供实时sub/pub接口. 完备. 可以完整...

dev5
今天
7
0
OpenJDK之CyclicBarrier

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CyclicBarrier是Doug Lea在JDK1.5中引入的,作用就不详细描述了,主要有如下俩个方法使用: await()方法,如果当前线...

克虏伯
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部