Spring學習日記十三------MVC M與C的實現篇

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 部分的分析了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章