Spring MVC 九大組件

九大組件說明

  • HandlerMapping(處理器映射器)
    HandlerMapping 是用來查找 Handler 的,也就是處理器,具體的表現(xiàn)形式可以是類,也可以是方法。比如,標(biāo)注了@RequestMapping的每個方法都可以看成是一個Handler。Handler負(fù)責(zé)具體實(shí)際的請求處理,在請求到達(dá)后,HandlerMapping 的作用便是找到請求相應(yīng)的處理器Handler 和 Interceptor.

  • HandlerAdapter(處理器適配器)
    HandlerAdapter 是一個適配器。因?yàn)?Spring MVC 中 Handler 可以是任意形式的,只要能處理請求即可。但是把請求交給 Servlet 的時候,由于 Servlet 的方法結(jié)構(gòu)都是doService(HttpServletRequest req,HttpServletResponse resp)形式的,要讓固定的 Servlet 處理方法調(diào)用 Handler 來進(jìn)行處理,便是 HandlerAdapter 的職責(zé)。

  • HandlerExceptionResolver
    HandlerExceptionResolver 用于處理 Handler 產(chǎn)生的異常情況。它的作用是根據(jù)異常設(shè)置ModelAndView,之后交給渲染方法進(jìn)行渲染,渲染方法會將 ModelAndView 渲染成頁面。

  • ViewResolver
    ViewResolver即視圖解析器,用于將String類型的視圖名和Locale解析為View類型的視圖,只有一個resolveViewName()方法。從方法的定義可以看出,Controller層返回的String類型視圖名viewName 最終會在這里被解析成為View。View是用來渲染頁面的,也就是說,它會將程序返回的參數(shù)和數(shù)據(jù)填入模板中,生成html件。ViewResolver 在這個過程主要完成兩件事情:ViewResolver 找到渲染所用的模板(第一件大事)和所用的技術(shù)(第二件大事,其實(shí)也就是找到視圖的類型,如JSP)并填入?yún)?shù)。默認(rèn)情況下,Spring MVC會自動為我們配置一個InternalResourceViewResolver,是針對 JSP 類型視圖的。

  • RequestToViewNameTranslator
    RequestToViewNameTranslator 組件的作用是從請求中獲取 ViewName.因?yàn)?ViewResolver 根據(jù)ViewName 查找 View,但有的 Handler 處理完成之后,沒有設(shè)置 View,也沒有設(shè)置 ViewName,便要通過這個組件從請求中查找 ViewName。

  • LocaleResolver
    ViewResolver 組件的 resolveViewName 方法需要兩個參數(shù),一個是視圖名,一個是 Locale。LocaleResolver 用于從請求中解析出 Locale,比如中國 Locale 是 zh-CN,用來表示一個區(qū)域。這個組件也是 i18n 的基礎(chǔ)。

  • ThemeResolver
    ThemeResolver 組件是用來解析主題的。主題是樣式、圖片及它們所形成的顯示效果的集合。Spring MVC 中一套主題對應(yīng)一個 properties文件,里面存放著與當(dāng)前主題相關(guān)的所有資源,如圖片、CSS樣式等。創(chuàng)建主題非常簡單,只需準(zhǔn)備好資源,然后新建一個“主題名.properties”并將資源設(shè)置進(jìn)去,放在classpath下,之后便可以在頁面中使用了。SpringMVC中與主題相關(guān)的類有ThemeResolver、ThemeSource和Theme。ThemeResolver負(fù)責(zé)從請求中解析出主題名,ThemeSource根據(jù)主題名找到具體的主題,其抽象也就是Theme,可以通過Theme來獲取主題和具體的資源。

  • MultipartResolver
    MultipartResolver 用于上傳請求,通過將普通的請求包裝成 MultipartHttpServletRequest 來實(shí)現(xiàn)。MultipartHttpServletRequest 可以通過 getFile()方法 直接獲得文件。如果上傳多個文件,還可以調(diào)用getFileMap()方法得到Map<FileName,F(xiàn)ile>這樣的結(jié)構(gòu),MultipartResolver 的作用就是封裝普通的請求,使其擁有文件上傳的功能。

  • FlashMapManager
    FlashMap用于重定向時的參數(shù)傳遞,比如在處理用戶訂單時候,為了避免重復(fù)提交,可以處理完post請求之后重定向到一個get請求,這個get請求可以用來顯示訂單詳情之類的信息。這樣做雖然可以規(guī)避用戶重新提交訂單的問題,但是在這個頁面上要顯示訂單的信息,這些數(shù)據(jù)從哪里來獲得呢?因?yàn)橹囟ㄏ驎r沒有傳遞參數(shù)這一功能的,如果不想把參數(shù)寫進(jìn)URL(不推薦),那么就可以通過FlashMap來傳遞。只需要在重定向之前將要傳遞的數(shù)據(jù)寫入請求(可以通過ServletRequestAttributes.getRequest()方法獲得)的屬性O(shè)UTPUT_FLASH_MAP_ATTRIBUTE中,這樣在重定向之后的Handler中Spring就會自動將其設(shè)置到Model中,在顯示訂單信息的頁面上就可以直接從Model中獲取數(shù)據(jù)。FlashMapManager 就是用來管理 FalshMap 的。

DispacherServlet.java 代碼中的相關(guān)說明

/** MultipartResolver used by this servlet. */
// 多部件解析器
@Nullable
private MultipartResolver multipartResolver;

/** LocaleResolver used by this servlet. */
// 區(qū)域化 國際化解析器
@Nullable
private LocaleResolver localeResolver;

/** ThemeResolver used by this servlet. */
// 主題解析器
@Nullable
private ThemeResolver themeResolver;

/** List of HandlerMappings used by this servlet. */
// 處理器映射器組件
@Nullable
private List<HandlerMapping> handlerMappings;

/** List of HandlerAdapters used by this servlet. */
// 處理器適配器組件
@Nullable
private List<HandlerAdapter> handlerAdapters;

/** List of HandlerExceptionResolvers used by this servlet. */
// 異常解析器組件
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;

/** RequestToViewNameTranslator used by this servlet. */
// 默認(rèn)視圖名轉(zhuǎn)換器組件
@Nullable
private RequestToViewNameTranslator viewNameTranslator;

/** FlashMapManager used by this servlet. */
// flash 屬性管理組件
@Nullable
private FlashMapManager flashMapManager;

/** List of ViewResolvers used by this servlet. */
// 視圖解析器
@Nullable
private List<ViewResolver> viewResolvers;
上述九大組件都是定義了接口,接口其實(shí)是定義了規(guī)范,比如ViewResolver、HandlerAdapter

等都是接口

九大組件的初始化時機(jī)

  • DispatcherServlet中的onRefresh(),該方法中初始化了九大組件
@Override
protected void onRefresh(ApplicationContext context) {
    // 初始化策略
    initStrategies(context);
}
  • initStrategies方法
protected void initStrategies(ApplicationContext context) {
    // 多文件上傳的組件
    initMultipartResolver(context);
    // 初始化本地語言環(huán)境
    initLocaleResolver(context);
    // 初始化模板處理器
    initThemeResolver(context);
    // 初始化HandlerMapping
    initHandlerMappings(context);
    // 初始化參數(shù)適配器
    initHandlerAdapters(context);
    // 初始化異常攔截器
    initHandlerExceptionResolvers(context);
    // 初始化視圖預(yù)處理器
    initRequestToViewNameTranslator(context);
    // 初始化視圖轉(zhuǎn)換器
    initViewResolvers(context);
    // 初始化 FlashMap 管理器
    initFlashMapManager(context);
}
  • 觀察其中的一個組件initHandlerMappings(context)
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        // 找到所有的HandlerMapping
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        try {
            // 否則在ioc中按照固定名稱去找
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    if (this.handlerMappings == null) {
        // 最后還為空則按照默認(rèn)策略生成
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
  • 如果按照類型和按照固定id從ioc容器中找不到對應(yīng)組件,則會按照默認(rèn)策略進(jìn)行注冊初始化,默認(rèn)策略在DispatcherServlet.properties文件中配置
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        for (String className : classNames) {
            try {
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                Object strategy = createDefaultStrategy(context, clazz);
                strategies.add((T) strategy);
            }
            catch (ClassNotFoundException ex) {
                throw new BeanInitializationException(
                        "Could not find DispatcherServlet's default strategy class [" + className +
                        "] for interface [" + key + "]", ex);
            }
            catch (LinkageError err) {
                throw new BeanInitializationException(
                        "Unresolvable class definition for DispatcherServlet's default strategy class [" +
                        className + "] for interface [" + key + "]", err);
            }
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}
  • DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
    org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
    org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
注意:多部件解析器的初始化必須按照 id 注冊對象(multipartResolver)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容