国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

SpringMVC源碼解讀之HandlerMapping

2019-11-26 14:32:44
字體:
來源:轉載
供稿:網友

概述

對于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 非常簡單.

// HandlerMappingpackage 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 WebApplicationObjectSupportimplements 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中解析得到,直接添加給全部handlerprivate final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();// 使用前需要跟url進行匹配,匹配通過才會使用private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>(); 

看下攔截器的初始化:

// AbstractHandlerMapping@Overrideprotected 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)給子類實現

// AbstractHandlerMappingpublic 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匹配通過后添加

// AbstractHandlerMappingprotected 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查找handlerprotected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {}// 校驗handlerprotected void validateHandler(Object handler, HttpServletRequest request) throws Exception {}// 封裝攔截器到HandlerExecutionChainprotected 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進行注冊

@Overridepublic 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

@Overrideprotected 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實例

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平谷区| 镇平县| 乐业县| 晋中市| 康马县| 上思县| 杭州市| 府谷县| 卢湾区| 郁南县| 神木县| 孝感市| 新竹县| 嘉兴市| 澎湖县| 当雄县| 蕲春县| 喀喇| 许昌县| 金溪县| 民权县| 甘洛县| 左贡县| 华蓥市| 云浮市| 永州市| 临夏县| 三河市| 阳城县| 大石桥市| 黄山市| 安庆市| 固阳县| 讷河市| 唐海县| 荆门市| 西平县| 丹寨县| 大兴区| 兴仁县| 丹寨县|