概述
對(duì)于Web開(kāi)發(fā)者,MVC模型是大家再熟悉不過(guò)的了,SpringMVC中,滿足條件的請(qǐng)求進(jìn)入到負(fù)責(zé)請(qǐng)求分發(fā)的DispatcherServlet,DispatcherServlet根據(jù)請(qǐng)求url到控制器的映射(HandlerMapping中保存),HandlerMapping最終返回HandlerExecutionChain,其中包含了具體的處理對(duì)象handler(也即我們編程時(shí)寫的controller)以及一系列的攔截器interceptors,此時(shí)DispatcherServlet會(huì)根據(jù)返回的HandlerExecutionChain中的handler找到支持這一處理器類型的適配器(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è)分類:
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 非常簡(jiǎn)單.
1
2
3
4
5
|
// HandlerMapping package org.springframework.web.servlet; public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; } |
AbstractHandlerMapping就沒(méi)有這么簡(jiǎn)單了
先看AbstractHandlerMapping繼承的類,實(shí)現(xiàn)的接口
1
2
3
4
5
|
package org.springframework.web.servlet.handler; public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { // ... } |
WebApplicationObjectSupport用于提供上下文ApplicationContext和ServletContext.
還有這邊的initApplicationContext方法,在后續(xù)經(jīng)常會(huì)使用到.AbstractHandlerMapping就直接覆寫了.
父類里還是實(shí)現(xiàn)了ApplicationContextAware和ServletContextAware接口,spring概念很統(tǒng)一.
Ordered用于集合排序.
再接著看AbstractHandlerMapping的屬性吧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// AbstractHandlerMapping // order賦了最大值,優(yōu)先級(jí)是最小的 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}場(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>(); |
看下攔截器的初始化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
// AbstractHandlerMapping @Override protected void initApplicationContext() throws BeansException { extendInterceptors( this .interceptors); detectMappedInterceptors( this .mappedInterceptors); initInterceptors(); } /** * 提供給子類擴(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)給子類實(shí)現(xiàn)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 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ò)后添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 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)說(shuō)說(shuō),這邊每個(gè)類主要的職責(zé)
1. AbstractHandlerMapping 準(zhǔn)備上下文環(huán)境;提供getHandlerInternal鉤子;封裝攔截器到HandlerExecutionChain
2. AbstractUrlHandlerMapping 實(shí)現(xiàn)注冊(cè)handler的方法供子類使用;實(shí)現(xiàn)getHandlerInternal,根據(jù)子類初始化的配置信息,查找handler
3. AbstractDetectingUrlHandlerMapping 掃描應(yīng)用下的Object,迭代后提供鉤子方法determineUrlsForHandler由子類決定如何過(guò)濾
4. AbstractControllerUrlHandlerMapping 實(shí)現(xiàn)determineUrlsForHandler,添加過(guò)濾排除的handler操作(配置文件配置),預(yù)留鉤子方法buildUrlsForHandler給子類實(shí)現(xiàn);同時(shí)判斷controller的子類
5. ControllerBeanNameHandlerMapping 根據(jù)bean name生成url
ControllerClassNameHandlerMapping根據(jù)class name生成url
從AbstractUrlHandlerMapping開(kāi)始看吧,這邊只是大致看下代碼,如果需要仔細(xì)分析,請(qǐng)移步<SpringMVC源碼解讀 - HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā)>
handler的注冊(cè)
1
2
|
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { } protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { } |
handler的查找
1
2
3
4
5
6
7
8
|
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ò)覆寫initApplicationContext,調(diào)用detectHandlers掃描Obejct
2. 提供鉤子方法determineUrlsForHandler給子類根據(jù)handler生成url
3. 調(diào)用父類的registerHandler進(jìn)行注冊(cè)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@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. 覆寫determineUrlsForHandler添加剔除部分類的邏輯,通過(guò)配置文件配置的excludedClasses和excludedPackages在這邊使用
2. 判斷是否controller的子類
3. 預(yù)留buildUrlsForHandler給子類生成url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@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的使用
最難吭的骨頭
先看類繼承吧
說(shuō)下各個(gè)類的職責(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鉤子方法給子類判斷Object是否handler
1.1.3 迭代掃描每一個(gè)handler,找出符合要求的方法,這邊判斷依然是留給子類實(shí)現(xiàn)getMappingForMethod
1.1.4 注冊(cè)查找到的處理器,需要確保一個(gè)匹配條件RequestMappingInfo只能映射到一個(gè)handler
1.1.5 根據(jù)匹配條件獲取url,同樣的只是定義流程,具體的算法留給子類實(shí)現(xiàn)getMappingPathPatterns
請(qǐng)求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
注冊(cè)pattern,最佳匹配的pattern,url中解析出來(lái)的參數(shù),url中解析出來(lái)的多值參數(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è)注解就對(duì)
3.3 解析注解內(nèi)容,生產(chǎn)RequestMappingInfo實(shí)例