SpringMVC源碼解讀之HandlerMapping
概述
對(duì)于Web開(kāi)發(fā)者,MVC模型是大家再熟悉不過(guò)的了,SpringMVC中,滿(mǎn)足條件的請(qǐng)求進(jìn)入到負(fù)責(zé)請(qǐng)求分發(fā)的DispatcherServlet,DispatcherServlet根據(jù)請(qǐng)求url到控制器的映射(HandlerMapping中保存),HandlerMapping最終返回HandlerExecutionChain,其中包含了具體的處理對(duì)象handler(也即我們編程時(shí)寫(xiě)的controller)以及一系列的攔截器interceptors,此時(shí)DispatcherServlet會(huì)根據(jù)返回的HandlerExecutionChain中的handler找到支持這一處理器類(lèi)型的適配器(handlerAdapter),在處理器適配器中最終會(huì)去調(diào)用控制器的請(qǐng)求響應(yīng)方法并返回結(jié)果視圖(ModelAndView),得到結(jié)果視圖后,通過(guò)render方法完成結(jié)果的顯示。
HanderMapping的繼承體系:
SpringMVC在請(qǐng)求到handler處理器的分發(fā)這步是通過(guò)HandlerMapping模塊解決的.handlerMapping 還處理攔截器.
先看看HandlerMapping的繼承樹(shù)吧
可以大致這樣做個(gè)分類(lèi):
1. 一個(gè)接口HandlerMapping,定義一個(gè)api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
2. 一個(gè)基礎(chǔ)抽象類(lèi):主要是準(zhǔn)備上下文環(huán)境,提供getHandlerInternal鉤子,封裝攔截器到HandlerExecutionChain
3. 基于注解@Controller,@RequestMapping的使用
4. 配置文件中直接配置url到 handler的SimpleUrlHandlerMapping
5. 默認(rèn)實(shí)現(xiàn)BeanNameUrlHandlerMapping
6. Controller子類(lèi)的映射
看看HandlerMapping吧,就一個(gè)getHandler api 非常簡(jiǎn)單.
// HandlerMapping package org.springframework.web.servlet; public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
AbstractHandlerMapping就沒(méi)有這么簡(jiǎn)單了
先看AbstractHandlerMapping繼承的類(lèi),實(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)常會(huì)使用到.AbstractHandlerMapping就直接覆寫(xiě)了.
父類(lèi)里還是實(shí)現(xiàn)了ApplicationContextAware和ServletContextAware接口,spring概念很統(tǒng)一.
Ordered用于集合排序.
再接著看AbstractHandlerMapping的屬性吧
// AbstractHandlerMapping // order賦了最大值,優(yōu)先級(jí)是最小的 private int order = Integer.MAX_VALUE; // default: same as non-Ordered // 默認(rèn)的Handler,這邊使用的Obejct,子類(lèi)實(shí)現(xiàn)的時(shí)候,使用HandlerMethod,HandlerExecutionChain等 private Object defaultHandler; // url計(jì)算的輔助類(lèi) private UrlPathHelper urlPathHelper = new UrlPathHelper(); // 基于ant進(jìn)行path匹配,解決如/books/{id}場(chǎng)景 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)行匹配,匹配通過(guò)才會(huì)使用 private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
看下攔截器的初始化:
// AbstractHandlerMapping @Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.mappedInterceptors); initInterceptors(); } /** * 提供給子類(lèi)擴(kuò)展攔截器,可惜都沒(méi)有使用 */ 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)給子類(lèi)實(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匹配通過(guò)后添加
// 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子類(lèi)的映射,這一分支先看類(lèi)繼承
我們來(lái)說(shuō)說(shuō),這邊每個(gè)類(lèi)主要的職責(zé)
1. AbstractHandlerMapping 準(zhǔn)備上下文環(huán)境;提供getHandlerInternal鉤子;封裝攔截器到HandlerExecutionChain
2. AbstractUrlHandlerMapping 實(shí)現(xiàn)注冊(cè)handler的方法供子類(lèi)使用;實(shí)現(xiàn)getHandlerInternal,根據(jù)子類(lèi)初始化的配置信息,查找handler
3. AbstractDetectingUrlHandlerMapping 掃描應(yīng)用下的Object,迭代后提供鉤子方法determineUrlsForHandler由子類(lèi)決定如何過(guò)濾
4. AbstractControllerUrlHandlerMapping 實(shí)現(xiàn)determineUrlsForHandler,添加過(guò)濾排除的handler操作(配置文件配置),預(yù)留鉤子方法buildUrlsForHandler給子類(lèi)實(shí)現(xiàn);同時(shí)判斷controller的子類(lèi)
5. ControllerBeanNameHandlerMapping 根據(jù)bean name生成url
ControllerClassNameHandlerMapping根據(jù)class name生成url
從AbstractUrlHandlerMapping開(kāi)始看吧,這邊只是大致看下代碼,如果需要仔細(xì)分析,請(qǐng)移步<SpringMVC源碼解讀 - HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā)>
handler的注冊(cè)
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,這邊一樣不展開(kāi),具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>
具體做的事情:
1. 通過(guò)覆寫(xiě)initApplicationContext,調(diào)用detectHandlers掃描Obejct
2. 提供鉤子方法determineUrlsForHandler給子類(lèi)根據(jù)handler生成url
3. 調(diào)用父類(lèi)的registerHandler進(jìn)行注冊(cè)
@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,這邊一樣不展開(kāi),具體移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>
具體做的事情;
1. 覆寫(xiě)determineUrlsForHandler添加剔除部分類(lèi)的邏輯,通過(guò)配置文件配置的excludedClasses和excludedPackages在這邊使用
2. 判斷是否controller的子類(lèi)
3. 預(yù)留buildUrlsForHandler給子類(lèi)生成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注冊(cè)配置文檔中的handler,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - SimpleUrlHandlerMapping初始化>吧
BeanNameUrlHandlerMapping 實(shí)現(xiàn)determineUrlsForHandler生成url,直接看代碼或者移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>吧
基于注解@Controller,@RequestMapping的使用
最難吭的骨頭
先看類(lèi)繼承吧
說(shuō)下各個(gè)類(lèi)的職責(zé)吧,具體的分析還是移步下面的文章
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping初始化>
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping請(qǐng)求分發(fā)>
1. AbstractHandlerMethodMaping 定義初始化流程,請(qǐng)求時(shí)如何映射
初始化:
1.1.1 掃描應(yīng)用下的Object
1.1.2 預(yù)留isHandler鉤子方法給子類(lèi)判斷Object是否handler
1.1.3 迭代掃描每一個(gè)handler,找出符合要求的方法,這邊判斷依然是留給子類(lèi)實(shí)現(xiàn)getMappingForMethod
1.1.4 注冊(cè)查找到的處理器,需要確保一個(gè)匹配條件RequestMappingInfo只能映射到一個(gè)handler
1.1.5 根據(jù)匹配條件獲取url,同樣的只是定義流程,具體的算法留給子類(lèi)實(shí)現(xiàn)getMappingPathPatterns
請(qǐng)求request分發(fā)處理:
1.2.1 直接字符串匹配的方式,查找handler
1.2.2 匹配條件查找,這邊具體的算法交由子類(lèi)處理getMatchingMapping
1.2.3 排序并獲取最佳匹配handler,這邊的排序方式還是子類(lèi)處理getMappingConmparator
1.2.4 分別封裝匹配到和未匹配到handler的情況
2. RequestMappingInfoHandlerMapping使用RequestMappingInfo實(shí)現(xiàn)匹配條件,RequestMappingInfo的初始化留給子類(lèi)
2.1 根據(jù)RequestMappingInfo生成url ->getMappingPathPatterns
2.2 使用匹配條件查找Handler -> getMatchingMapping
2.3 完成比較器算法 -> getMappingComparator
2.4 覆寫(xiě)handleMatch,緩存n多信息到request
注冊(cè)pattern,最佳匹配的pattern,url中解析出來(lái)的參數(shù),url中解析出來(lái)的多值參數(shù),mediaType
2.1.5 覆寫(xiě)handlerNoMatch,最后的掙扎,再?lài)L試匹配一次
3. RequestMappingHandlerMapping 根據(jù)注解@Controller @RequestMapping生成RequestMappingInfo,并校驗(yàn)isHandler
3.1 覆寫(xiě)afterPropertiesSet,添加文件后綴判斷
3.2 實(shí)現(xiàn)isHandler,類(lèi)上有@Controller @RequestMapping其中一個(gè)注解就對(duì)
3.3 解析注解內(nèi)容,生產(chǎn)RequestMappingInfo實(shí)例
相關(guān)文章
java通過(guò)Callable和Future來(lái)接收線(xiàn)程池的執(zhí)行結(jié)果
這篇文章主要介紹了java通過(guò)Callable和Future來(lái)接收線(xiàn)程池的執(zhí)行結(jié)果,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08SpringSecurity?Web權(quán)限方案實(shí)現(xiàn)全過(guò)程
Spring Security是一個(gè)功能強(qiáng)大且高度可定制的身份驗(yàn)證和授權(quán)框架,專(zhuān)門(mén)用于保護(hù)Java應(yīng)用程序的Web集成,下面這篇文章主要給大家介紹了關(guān)于SpringSecurity?Web權(quán)限方案實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2024-01-01seata-1.4.0安裝及在springcloud中使用詳解
這篇文章主要介紹了seata-1.4.0安裝及在springcloud中使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志示例
這篇文章主要為大家介紹了spring boot整合log4j2及MQ消費(fèi)處理系統(tǒng)日志的示例過(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Spring使用AspectJ注解和XML配置實(shí)現(xiàn)AOP
這篇文章主要介紹了Spring使用AspectJ注解和XML配置實(shí)現(xiàn)AOP的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Java數(shù)據(jù)結(jié)構(gòu)之二叉查找樹(shù)的實(shí)現(xiàn)
二叉查找樹(shù)(亦稱(chēng)二叉搜索樹(shù)、二叉排序樹(shù))是一棵二叉樹(shù),且各結(jié)點(diǎn)關(guān)鍵詞互異,其中根序列按其關(guān)鍵詞遞增排列。本文將通過(guò)示例詳細(xì)講解二叉查找樹(shù),感興趣的可以了解一下2022-03-03