SpringMVC源碼解讀之HandlerMapping。本站提示廣大學習愛好者:(SpringMVC源碼解讀之HandlerMapping)文章只能為提供參考,不一定能成為您想要的結果。以下是SpringMVC源碼解讀之HandlerMapping正文
概述
關於Web開辟者,MVC模子是年夜家再熟習不外的了,SpringMVC中,知足前提的要求進入到擔任要求分發的DispatcherServlet,DispatcherServlet依據要求url到掌握器的映照(HandlerMapping中保留),HandlerMapping終究前往HandlerExecutionChain,個中包括了詳細的處置對象handler(也即我們編程時寫的controller)和一系列的攔阻器interceptors,此時DispatcherServlet會依據前往的HandlerExecutionChain中的handler找到支撐這一處置器類型的適配器(handlerAdapter),在處置器適配器中終究會去挪用掌握器的要求呼應辦法並前往成果視圖(ModelAndView),獲得成果視圖後,經由過程render辦法完成成果的顯示。
HanderMapping的繼續系統:
SpringMVC在要求到handler處置器的分發這步是經由過程HandlerMapping模塊處理的.handlerMapping 還處置攔阻器.
先看看HandlerMapping的繼續樹吧
可以年夜致如許做個分類:
1. 一個接口HandlerMapping,界說一個api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
2. 一個基本籠統類:重要是預備高低文情況,供給getHandlerInternal鉤子,封裝攔阻器到HandlerExecutionChain
3. 基於注解@Controller,@RequestMapping的應用
4. 設置裝備擺設文件中直接設置裝備擺設url到 handler的SimpleUrlHandlerMapping
5. 默許完成BeanNameUrlHandlerMapping
6. Controller子類的映照
看看HandlerMapping吧,就一個getHandler api 異常簡略.
// HandlerMapping package org.springframework.web.servlet; public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
AbstractHandlerMapping就沒有這麼簡略了
先看AbstractHandlerMapping繼續的類,完成的接口
package org.springframework.web.servlet.handler; public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { // ... }
WebApplicationObjectSupport用於供給高低文ApplicationContext和ServletContext.
還有這邊的initApplicationContext辦法,在後續常常會應用到.AbstractHandlerMapping就直接覆寫了.
父類裡照樣完成了ApplicationContextAware和ServletContextAware接口,spring概念很同一.
Ordered用於聚集排序.
再接著看AbstractHandlerMapping的屬性吧
// AbstractHandlerMapping // order賦了最年夜值,優先級是最小的 private int order = Integer.MAX_VALUE; // default: same as non-Ordered // 默許的Handler,這邊應用的Obejct,子類完成的時刻,應用HandlerMethod,HandlerExecutionChain等 private Object defaultHandler; // url盤算的幫助類 private UrlPathHelper urlPathHelper = new UrlPathHelper(); // 基於ant停止path婚配,處理如/books/{id}場景 private PathMatcher pathMatcher = new AntPathMatcher(); // 攔阻器設置裝備擺設:,HandlerMapping屬性設置;,extendInterceptors設置 private final List<Object> interceptors = new ArrayList<Object>(); // 從interceptors中解析獲得,直接添加給全體handler private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>(); // 應用前須要跟url停止婚配,婚配經由過程才會應用 private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
看下攔阻器的初始化:
// AbstractHandlerMapping @Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.mappedInterceptors); initInterceptors(); } /** * 供給給子類擴大攔阻器,惋惜都沒有應用 */ protected void extendInterceptors(List<Object> interceptors) { } /** * 掃描運用下的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)的完成,這邊同時預留getHandlerInternal(HttpServletRequest request)給子類完成
// 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須要依據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子類的映照,這一分支先看類繼續
我們來講說,這邊每一個類重要的職責
1. AbstractHandlerMapping 預備高低文情況;供給getHandlerInternal鉤子;封裝攔阻器到HandlerExecutionChain
2. AbstractUrlHandlerMapping 完成注冊handler的辦法供子類應用;完成getHandlerInternal,依據子類初始化的設置裝備擺設信息,查找handler
3. AbstractDetectingUrlHandlerMapping 掃描運用下的Object,迭代後供給鉤子辦法determineUrlsForHandler由子類決議若何過濾
4. AbstractControllerUrlHandlerMapping 完成determineUrlsForHandler,添加過濾消除的handler操作(設置裝備擺設文件設置裝備擺設),預留鉤子辦法buildUrlsForHandler給子類完成;同時斷定controller的子類
5. ControllerBeanNameHandlerMapping 依據bean name生成url
ControllerClassNameHandlerMapping依據class name生成url
從AbstractUrlHandlerMapping開端看吧,這邊只是年夜致看下代碼,假如須要細心剖析,請移步<SpringMVC源碼解讀 - HandlerMapping - AbstractUrlHandlerMapping系列request分發>
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 {} // 依據url查找handler protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {} // 校驗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,挪用detectHandlers掃描Obejct
2. 供給鉤子辦法determineUrlsForHandler給子類依據handler生成url
3. 挪用父類的registerHandler停止注冊
@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. 預留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 完成determineUrlsForHandler生成url,直接看代碼或許移步<SpringMVC源碼解讀 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>吧
基於注解@Controller,@RequestMapping的應用
最難吭的骨頭
先看類繼續吧
說下各個類的職責吧,詳細的剖析照樣移步上面的文章
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping初始化>
<SpringMVC源碼解讀 - HandlerMapping - RequestMappingHandlerMapping要求分發>
1. AbstractHandlerMethodMaping 界說初始化流程,要求時若何映照
初始化:
1.1.1 掃描運用下的Object
1.1.2 預留isHandler鉤子辦法給子類斷定Object能否handler
1.1.3 迭代掃描每個handler,找出相符請求的辦法,這邊斷定仍然是留給子類完成getMappingForMethod
1.1.4 注冊查找到的處置器,須要確保一個婚配前提RequestMappingInfo只能映照到一個handler
1.1.5 依據婚配前提獲得url,異樣的只是界說流程,詳細的算法留給子類完成getMappingPathPatterns
要求request分發處置:
1.2.1 直接字符串婚配的方法,查找handler
1.2.2 婚配前提查找,這邊詳細的算法交由子類處置getMatchingMapping
1.2.3 排序並獲得最好婚配handler,這邊的排序方法照樣子類處置getMappingConmparator
1.2.4 分離封裝婚配到和未婚配到handler的情形
2. RequestMappingInfoHandlerMapping應用RequestMappingInfo完成婚配前提,RequestMappingInfo的初始化留給子類
2.1 依據RequestMappingInfo生成url ->getMappingPathPatterns
2.2 應用婚配前提查找Handler -> getMatchingMapping
2.3 完成比擬器算法 -> getMappingComparator
2.4 覆寫handleMatch,緩存n多信息到request
注冊pattern,最好婚配的pattern,url中解析出來的參數,url中解析出來的多值參數,mediaType
2.1.5 覆寫handlerNoMatch,最初的掙扎,再測驗考試婚配一次
3. RequestMappingHandlerMapping 依據注解@Controller @RequestMapping生成RequestMappingInfo,並校驗isHandler
3.1 覆寫afterPropertiesSet,添加文件後綴斷定
3.2 完成isHandler,類上有@Controller @RequestMapping個中一個注解就對
3.3 解析注解內容,臨盆RequestMappingInfo實例