歡迎光臨
每天分享高質量文章

看透 Spring MVC 原始碼分析與實踐 —— Spring MVC 元件分析

元件概覽

HandlerMapping

根據 request 找到對應的處理器 Handler 和 Interceptors。內部只有一個方法

  1. HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

HandlerAdapter

Handler 配接器,內部方法如下:

  1. boolean supports(Object handler);//判斷是否可以使用某個 Handler

  2. ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //具體使用

  3. long getLastModified(HttpServletRequest request, Object handler);//獲取資源上一次修改的時間

HandlerExceptionResolver

根據異常設定 ModelAndView ,再交給 render 方法進行渲染。

  1. ModelAndView resolveException(

  2.            HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex)

ViewResolver

用來將 String 型別的檢視名和 Locale 解析為 View 型別的檢視。

  1. View resolveViewName(String viewName, Locale locale) throws Exception;

它的一個實現類 BeanNameViewResolver,它重寫 resolveViewName 方法如下:

  1. public View resolveViewName(String viewName, Locale locale) throws BeansException {

  2.        ApplicationContext context = getApplicationContext();

  3.        //如果應用背景關係沒有找到檢視,傳回 null

  4.        if (!context.containsBean(viewName)) {

  5.            if (logger.isDebugEnabled()) {

  6.                logger.debug("No matching bean found for view name '" + viewName + "'");

  7.            }

  8.            // Allow for ViewResolver chaining...

  9.            return null;

  10.        }

  11.        //如果找到的檢視型別不匹配,也傳回 null

  12.        if (!context.isTypeMatch(viewName, View.class)) {

  13.            if (logger.isDebugEnabled()) {

  14.                logger.debug("Found matching bean for view name '" + viewName +

  15.                        "' - to be ignored since it does not implement View");

  16.            }

  17.            // Since we're looking into the general ApplicationContext here,

  18.            // let's accept this as a non-match and allow for chaining as well...

  19.            return null;

  20.        }

  21.        //根據檢視名稱從 Spring 容器中查詢 Bean,傳回找到的 bean

  22.        return context.getBean(viewName, View.class);

  23.    }

RequestToViewNameTranslator

獲取 request 中的檢視名。介面裡面也是隻有一個方法:

  1. String getViewName(HttpServletRequest request) throws Exception; //根據 request 查詢檢視名

LocaleResolver

用於從 request 解析出 Locale。

  1. public interface LocaleResolver {

  2.      //從 request 解析出 Locale

  3.    Locale resolveLocale(HttpServletRequest request);

  4.      //根據 request 設定  locale

  5.    void setLocale(HttpServletRequest request, HttpServletResponse response, @Nullable Locale locale);

  6. }

ThemeResolver

解析主題

  1. public interface ThemeResolver {

  2.    //透過給定的 request 查詢主題名

  3.    String resolveThemeName(HttpServletRequest request);

  4.    //根據給定的 request 設定主題名

  5.    void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);

  6. }

在 RequestContext.java 檔案中可以獲取主題:

  1. public String getThemeMessage(String code, String defaultMessage) {

  2.        //獲取主題的資訊

  3.        return getTheme().getMessageSource().getMessage(code, null, defaultMessage, this.locale);

  4.    }

  5. public Theme getTheme() {

  6.        //判斷主題是否為空

  7.        if (this.theme == null) {

  8.            // 透過 RequestContextUtils 獲取 request 中的主題名

  9.            this.theme = RequestContextUtils.getTheme(this.request);

  10.            if (this.theme == null) {   //如果還是為空的話

  11.                //那就是沒有有效的主題解析器和主題

  12.                this.theme = getFallbackTheme();

  13.            }

  14.        }

  15.        return this.theme;

  16.    }

RequestContextUtils.getTheme() 方法:

  1. public static Theme getTheme(HttpServletRequest request) {

  2.        ThemeResolver themeResolver = getThemeResolver(request);

  3.        ThemeSource themeSource = getThemeSource(request);

  4.        if (themeResolver != null && themeSource != null) {

  5.            String themeName = themeResolver.resolveThemeName(request);

  6.            return themeSource.getTheme(themeName);

  7.        }

  8.        else {

  9.            return null;

  10.        }

  11.    }

MultipartResolver

用於處理上傳請求,處理方法:將普通的 request 包裝成 MultipartHttpServletRequest

  1. public interface MultipartResolver {

  2.    //根據 request 判斷是否是上傳請求

  3.    boolean isMultipart(HttpServletRequest request);

  4.    //將 request 包裝成 MultipartHttpServletRequest

  5.    MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;

  6.    //清理上傳過程中產生的臨時資源

  7.    void cleanupMultipart(MultipartHttpServletRequest request);

  8. }

FlashMapManager

FlashMap 主要在 redirect 中傳遞引數,FlashMapManager 用來管理 FlashMap 的。

  1. public interface FlashMapManager {

  2.    //恢復引數,並將恢復過的和超時的引數從儲存介質中刪除

  3.    @Nullable

  4.    FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);

  5.    //將引數儲存起來

  6.    void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);

  7. }

小結

介紹 Spring MVC 中九大元件的介面、作用、內部方法實現及作用進行了簡單的介紹,詳細的還需大家自己去看原始碼。


友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。
友情提示:歡迎關註公眾號【芋道原始碼】。?關註後,拉你進【原始碼圈】微信群討論技術和原始碼。


總結

Spring MVC 原理總結

本質是一個 Servlet,這個 Servlet 繼承自 HttpServlet。Spring MVC 中提供了三個層次的 Servlet:HttpServletBean、FrameworkServlet 和 DispatcherServlet。他們相互繼承, HttpServletBean 直接繼承自 Java 的 HttpServlet。HttpServletBean 用於將 Servlet 中的 Servlet 中配置的引數設定到相應的屬性中,FrameworkServlet 初始化了 Spring MVC 中所使用的 WebApplicationContext,具體處理請求的 9 大元件是在 DispatcherServlet 中初始化的,整個繼承圖如下:

相關文章

看透 Spring MVC 原始碼分析與實踐 —— 網站基礎知識

看透 Spring MVC 原始碼分析與實踐 —— SpringMVC 之初體驗

贊(0)

分享創造快樂