欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringMVC源碼解讀之HandlerMapping

 更新時(shí)間:2016年02月25日 09:31:18   作者:出門向左  
這篇文章主要介紹了SpringMVC源碼解讀之HandlerMapping 的相關(guān)資料,需要的朋友可以參考下

概述

對于Web開發(fā)者,MVC模型是大家再熟悉不過的了,SpringMVC中,滿足條件的請求進(jìn)入到負(fù)責(zé)請求分發(fā)的DispatcherServlet,DispatcherServlet根據(jù)請求url到控制器的映射(HandlerMapping中保存),HandlerMapping最終返回HandlerExecutionChain,其中包含了具體的處理對象handler(也即我們編程時(shí)寫的controller)以及一系列的攔截器interceptors,此時(shí)DispatcherServlet會根據(jù)返回的HandlerExecutionChain中的handler找到支持這一處理器類型的適配器(handlerAdapter),在處理器適配器中最終會去調(diào)用控制器的請求響應(yīng)方法并返回結(jié)果視圖(ModelAndView),得到結(jié)果視圖后,通過render方法完成結(jié)果的顯示。

HanderMapping的繼承體系:

SpringMVC在請求到handler處理器的分發(fā)這步是通過HandlerMapping模塊解決的.handlerMapping 還處理攔截器.

先看看HandlerMapping的繼承樹吧

可以大致這樣做個(gè)分類:

  1. 一個(gè)接口HandlerMapping,定義一個(gè)api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

  2. 一個(gè)基礎(chǔ)抽象類:主要是準(zhǔn)備上下文環(huán)境,提供getHandlerInternal鉤子,封裝攔截器到HandlerExecutionChain

  3. 基于注解@Controller,@RequestMapping的使用

  4. 配置文件中直接配置url到 handler的SimpleUrlHandlerMapping

  5. 默認(rèn)實(shí)現(xiàn)BeanNameUrlHandlerMapping

  6. Controller子類的映射

看看HandlerMapping吧,就一個(gè)getHandler api 非常簡單.

// HandlerMapping
package org.springframework.web.servlet;
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

AbstractHandlerMapping就沒有這么簡單了

先看AbstractHandlerMapping繼承的類,實(shí)現(xiàn)的接口

package org.springframework.web.servlet.handler;
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
implements HandlerMapping, Ordered {
// ...
}

WebApplicationObjectSupport用于提供上下文ApplicationContext和ServletContext.

  還有這邊的initApplicationContext方法,在后續(xù)經(jīng)常會使用到.AbstractHandlerMapping就直接覆寫了.

  父類里還是實(shí)現(xiàn)了ApplicationContextAware和ServletContextAware接口,spring概念很統(tǒng)一.

Ordered用于集合排序.

再接著看AbstractHandlerMapping的屬性吧

// AbstractHandlerMapping
// order賦了最大值,優(yōu)先級是最小的
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
// 默認(rèn)的Handler,這邊使用的Obejct,子類實(shí)現(xiàn)的時(shí)候,使用HandlerMethod,HandlerExecutionChain等
private Object defaultHandler;
// url計(jì)算的輔助類
private UrlPathHelper urlPathHelper = new UrlPathHelper();
// 基于ant進(jìn)行path匹配,解決如/books/{id}場景
private PathMatcher pathMatcher = new AntPathMatcher();
// 攔截器配置:,HandlerMapping屬性設(shè)置;,extendInterceptors設(shè)置
private final List<Object> interceptors = new ArrayList<Object>();
// 從interceptors中解析得到,直接添加給全部handler
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
// 使用前需要跟url進(jìn)行匹配,匹配通過才會使用
private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>(); 

看下攔截器的初始化:

// AbstractHandlerMapping
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.mappedInterceptors);
initInterceptors();
}
/**
* 提供給子類擴(kuò)展攔截器,可惜都沒有使用
*/
protected void extendInterceptors(List<Object> interceptors) {
}
/**
* 掃描應(yīng)用下的MappedInterceptor,并添加到mappedInterceptors
*/
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(),MappedInterceptor.class, true, false).values());
}
/**
* 歸集MappedInterceptor,并適配HandlerInterceptor和WebRequestInterceptor
*/
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = ; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
if (interceptor instanceof MappedInterceptor) {
mappedInterceptors.add((MappedInterceptor) interceptor);
}
else {
adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
}
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
}
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
}
else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}

然后是getHandler(HttpServletRequest request)的實(shí)現(xiàn),這邊同時(shí)預(yù)留getHandlerInternal(HttpServletRequest request)給子類實(shí)現(xiàn)

// AbstractHandlerMapping
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception; 

最后是封裝攔截器到HandlerExecutionChain

  adaptedInterceptors直接添加

  mappedInterceptors需要根據(jù)url匹配通過后添加

// AbstractHandlerMapping
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain =
(handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
} 

Controller子類的映射,這一分支先看類繼承

我們來說說,這邊每個(gè)類主要的職責(zé)

  1. AbstractHandlerMapping 準(zhǔn)備上下文環(huán)境;提供getHandlerInternal鉤子;封裝攔截器到HandlerExecutionChain

  2. AbstractUrlHandlerMapping 實(shí)現(xiàn)注冊handler的方法供子類使用;實(shí)現(xiàn)getHandlerInternal,根據(jù)子類初始化的配置信息,查找handler

  3. AbstractDetectingUrlHandlerMapping 掃描應(yīng)用下的Object,迭代后提供鉤子方法determineUrlsForHandler由子類決定如何過濾

  4. AbstractControllerUrlHandlerMapping 實(shí)現(xiàn)determineUrlsForHandler,添加過濾排除的handler操作(配置文件配置),預(yù)留鉤子方法buildUrlsForHandler給子類實(shí)現(xiàn);同時(shí)判斷controller的子類

  5. ControllerBeanNameHandlerMapping 根據(jù)bean name生成url

    ControllerClassNameHandlerMapping根據(jù)class name生成url

從AbstractUrlHandlerMapping開始看吧,這邊只是大致看下代碼,如果需要仔細(xì)分析,請移步<SpringMVC源碼解讀 - HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā)>

handler的注冊

protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { }
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { } 

handler的查找

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {}
// 根據(jù)url查找handler
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {}
// 校驗(yàn)handler
protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {}
// 封裝攔截器到HandlerExecutionChain
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {} 

AbstractDetectingUrlHandlerMapping,這邊一樣不展開,具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

具體做的事情:

  1. 通過覆寫initApplicationContext,調(diào)用detectHandlers掃描Obejct

  2. 提供鉤子方法determineUrlsForHandler給子類根據(jù)handler生成url

  3. 調(diào)用父類的registerHandler進(jìn)行注冊

@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
protected void detectHandlers() throws BeansException {
// ...
}
/**
* Determine the URLs for the given handler bean.
* 鉤子而已
*/
protected abstract String[] determineUrlsForHandler(String beanName); 

AbstractControllerUrlHandlerMapping,這邊一樣不展開,具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

具體做的事情;

  1. 覆寫determineUrlsForHandler添加剔除部分類的邏輯,通過配置文件配置的excludedClasses和excludedPackages在這邊使用

  2. 判斷是否controller的子類

  3. 預(yù)留buildUrlsForHandler給子類生成url

@Override
protected String[] determineUrlsForHandler(String beanName) {
Class beanClass = getApplicationContext().getType(beanName);
if (isEligibleForMapping(beanName, beanClass)) {
return buildUrlsForHandler(beanName, beanClass);
}
else {
return null;
}
}
protected boolean isEligibleForMapping(String beanName, Class beanClass) {}
protected boolean isControllerType(Class beanClass) {}
protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass); 

ControllerBeanNameHandlerMapping和ControllerClassNameHandlerMapping 直接看源碼吧,或者移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

配置文件中直接配置url到 handler的SimpleUrlHandlerMapping,就是使用registerHandlers注冊配置文檔中的handler,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - SimpleUrlHandlerMapping初始化>吧

BeanNameUrlHandlerMapping 實(shí)現(xiàn)determineUrlsForHandler生成url,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>吧

基于注解@Controller,@RequestMapping的使用

最難吭的骨頭

先看類繼承吧

說下各個(gè)類的職責(zé)吧,具體的分析還是移步下面的文章

<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping初始化>

<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping請求分發(fā)>

  1. AbstractHandlerMethodMaping 定義初始化流程,請求時(shí)如何映射

  初始化:

    1.1.1 掃描應(yīng)用下的Object

    1.1.2 預(yù)留isHandler鉤子方法給子類判斷Object是否handler

    1.1.3 迭代掃描每一個(gè)handler,找出符合要求的方法,這邊判斷依然是留給子類實(shí)現(xiàn)getMappingForMethod

    1.1.4 注冊查找到的處理器,需要確保一個(gè)匹配條件RequestMappingInfo只能映射到一個(gè)handler

    1.1.5 根據(jù)匹配條件獲取url,同樣的只是定義流程,具體的算法留給子類實(shí)現(xiàn)getMappingPathPatterns

  請求request分發(fā)處理:

    1.2.1 直接字符串匹配的方式,查找handler 

    1.2.2 匹配條件查找,這邊具體的算法交由子類處理getMatchingMapping

    1.2.3 排序并獲取最佳匹配handler,這邊的排序方式還是子類處理getMappingConmparator

   1.2.4 分別封裝匹配到和未匹配到handler的情況

  2. RequestMappingInfoHandlerMapping使用RequestMappingInfo實(shí)現(xiàn)匹配條件,RequestMappingInfo的初始化留給子類

    2.1 根據(jù)RequestMappingInfo生成url ->getMappingPathPatterns

    2.2 使用匹配條件查找Handler -> getMatchingMapping

    2.3 完成比較器算法 -> getMappingComparator

    2.4 覆寫handleMatch,緩存n多信息到request

      注冊pattern,最佳匹配的pattern,url中解析出來的參數(shù),url中解析出來的多值參數(shù),mediaType

    2.1.5 覆寫handlerNoMatch,最后的掙扎,再嘗試匹配一次

  3. RequestMappingHandlerMapping 根據(jù)注解@Controller @RequestMapping生成RequestMappingInfo,并校驗(yàn)isHandler

    3.1 覆寫afterPropertiesSet,添加文件后綴判斷

    3.2 實(shí)現(xiàn)isHandler,類上有@Controller @RequestMapping其中一個(gè)注解就對

    3.3 解析注解內(nèi)容,生產(chǎn)RequestMappingInfo實(shí)例

相關(guān)文章

  • java通過Callable和Future來接收線程池的執(zhí)行結(jié)果

    java通過Callable和Future來接收線程池的執(zhí)行結(jié)果

    這篇文章主要介紹了java通過Callable和Future來接收線程池的執(zhí)行結(jié)果,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringSecurity?Web權(quán)限方案實(shí)現(xiàn)全過程

    SpringSecurity?Web權(quán)限方案實(shí)現(xiàn)全過程

    Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和授權(quán)框架,專門用于保護(hù)Java應(yīng)用程序的Web集成,下面這篇文章主要給大家介紹了關(guān)于SpringSecurity?Web權(quán)限方案實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • seata-1.4.0安裝及在springcloud中使用詳解

    seata-1.4.0安裝及在springcloud中使用詳解

    這篇文章主要介紹了seata-1.4.0安裝及在springcloud中使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java實(shí)現(xiàn)的串口通信功能示例

    Java實(shí)現(xiàn)的串口通信功能示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的串口通信功能,結(jié)合實(shí)例形式分析了java串口通信的具體操作步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2018-01-01
  • java根據(jù)富文本生成pdf文件過程解析

    java根據(jù)富文本生成pdf文件過程解析

    這篇文章主要介紹了java根據(jù)富文本生成pdf文件過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志示例

    spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志示例

    這篇文章主要為大家介紹了spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志的示例過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • Spring使用AspectJ注解和XML配置實(shí)現(xiàn)AOP

    Spring使用AspectJ注解和XML配置實(shí)現(xiàn)AOP

    這篇文章主要介紹了Spring使用AspectJ注解和XML配置實(shí)現(xiàn)AOP的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Java數(shù)據(jù)結(jié)構(gòu)之二叉查找樹的實(shí)現(xiàn)

    Java數(shù)據(jù)結(jié)構(gòu)之二叉查找樹的實(shí)現(xiàn)

    二叉查找樹(亦稱二叉搜索樹、二叉排序樹)是一棵二叉樹,且各結(jié)點(diǎn)關(guān)鍵詞互異,其中根序列按其關(guān)鍵詞遞增排列。本文將通過示例詳細(xì)講解二叉查找樹,感興趣的可以了解一下
    2022-03-03
  • Java鎖擦除與鎖粗化概念和使用詳解

    Java鎖擦除與鎖粗化概念和使用詳解

    這篇文章主要介紹了Java鎖擦除與鎖粗化概念和使用,鎖擦除的主要判定依據(jù)來源于逃逸分析的數(shù)據(jù)支持,如果判斷在一段代碼中,堆上的所有數(shù)據(jù)都不會逃逸出去從而被其他線程訪問到,那就可以把它們當(dāng)做棧上數(shù)據(jù)對待,認(rèn)為它們是線程私有的,同步加鎖自然就無須進(jìn)行
    2023-02-02
  • SpringBoot使用Log4j過程詳解

    SpringBoot使用Log4j過程詳解

    這篇文章主要介紹了SpringBoot使用Log4j過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02

最新評論