SpringMVC源碼解讀之HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā)
AbstractHandlerMapping實(shí)現(xiàn)HandlerMapping接口定的getHandler
1. 提供getHandlerInternal模板方法給子類實(shí)現(xiàn)
2. 如果沒有獲取Handler,則使用默認(rèn)的defaultHandler
3. 如果handler是string類型,從context獲取實(shí)例
4. 通過getHandlerExecutionChain封裝handler,添加interceptor
// AbstractHandlerMapping /** * Look up a handler for the given request, falling back to the default * handler if no specific one is found. * @param request current HTTP request * @return the corresponding handler instance, or the default handler * @see #getHandlerInternal */ 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); } // AbstractHandlerMapping /** * Build a HandlerExecutionChain for the given handler, including applicable interceptors. * <p>The default implementation simply builds a standard HandlerExecutionChain with * the given handler, the handler mapping's common interceptors, and any {@link MappedInterceptor}s * matching to the current request URL. Subclasses may * override this in order to extend/rearrange the list of interceptors. * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built * HandlerExecutionChain. This method should handle those two cases explicitly, * either building a new HandlerExecutionChain or extending the existing chain. * <p>For simply adding an interceptor, consider calling {@code super.getHandlerExecutionChain} * and invoking {@link HandlerExecutionChain#addInterceptor} on the returned chain object. * @param handler the resolved handler instance (never {@code null}) * @param request current HTTP request * @return the HandlerExecutionChain (never {@code null}) * @see #getAdaptedInterceptors() */ 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; }
接下來看看AbstractUrlHandlerMapping實(shí)現(xiàn)的getHandlerInternal
// AbstractUrlHandlerMapping /** * Look up a handler for the URL path of the given request. * @param request current HTTP request * @return the handler instance, or {@code null} if none found */ @Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { // 根據(jù)request獲取url String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); // 根據(jù)url查找handler Object handler = lookupHandler(lookupPath, request); if (handler == null) { // 如果沒有匹配到handler需要查找默認(rèn)的,下面需要將PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE緩存到request // We need to care for the default handler directly, since we need to // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well. Object rawHandler = null; if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } if (rawHandler == null) { rawHandler = getDefaultHandler(); } if (rawHandler != null) { // Bean name or resolved handler? if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = getApplicationContext().getBean(handlerName); } // 預(yù)留的校驗(yàn)handler模板方法,沒有使用 validateHandler(rawHandler, request); // 添加expose屬性到request的攔截器 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } if (handler != null && logger.isDebugEnabled()) { logger.debug("Mapping [" + lookupPath + "] to " + handler); } else if (handler == null && logger.isTraceEnabled()) { logger.trace("No handler mapping found for [" + lookupPath + "]"); } return handler; } // AbstractUrlHandlerMapping /** * Look up a handler instance for the given URL path. * <p>Supports direct matches, e.g. a registered "/test" matches "/test", * and various Ant-style pattern matches, e.g. a registered "/t*" matches * both "/test" and "/team". For details, see the AntPathMatcher class. * <p>Looks for the most exact pattern, where most exact is defined as * the longest path pattern. * @param urlPath URL the bean is mapped to * @param request current HTTP request (to expose the path within the mapping to) * @return the associated handler instance, or {@code null} if not found * @see #exposePathWithinMapping * @see org.springframework.util.AntPathMatcher */ protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? 直接根據(jù)url進(jìn)行查找handler Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // Pattern match? 通過表達(dá)式進(jìn)行匹配具體通過AntPathMatcher實(shí)現(xiàn),具體后面分析 List<String> matchingPatterns = new ArrayList<String>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } } String bestPatternMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } // order序號最小的優(yōu)先級最高 bestPatternMatch = matchingPatterns.get(); } if (bestPatternMatch != null) { handler = this.handlerMap.get(bestPatternMatch); // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestPatternMatch, matchingPattern) == ) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } if (logger.isDebugEnabled()) { logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }
設(shè)計用于校驗(yàn)Handler,實(shí)際什么都沒做,包括子類.
/** * Validate the given handler against the current request. * <p>The default implementation is empty. Can be overridden in subclasses, * for example to enforce specific preconditions expressed in URL mappings. * @param handler the handler object to validate * @param request current HTTP request * @throws Exception if validation failed */ protected void validateHandler(Object handler, HttpServletRequest request) throws Exception { }
封裝handler為HandlerExecutionChain,并添加PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor攔截器.
/** * Build a handler object for the given raw handler, exposing the actual * handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as * the {@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE} before executing the handler. * <p>The default implementation builds a {@link HandlerExecutionChain} * with a special interceptor that exposes the path attribute and uri template variables * @param rawHandler the raw handler to expose * @param pathWithinMapping the path to expose before executing the handler * @param uriTemplateVariables the URI template variables, can be {@code null} if no variables found * @return the final handler object */ protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, String pathWithinMapping, Map<String, String> uriTemplateVariables) { HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping)); if (!CollectionUtils.isEmpty(uriTemplateVariables)) { chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables)); } return chain; }
以上內(nèi)容是小編給大家介紹的SpringMVC源碼解讀之HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā)的相關(guān)知識,希望對大家有所幫助!
- springmvc中RequestMappingHandlerAdapter與HttpMessageConverter的裝配講解
- Spring MVC學(xué)習(xí)教程之RequestMappingHandlerAdapter詳解
- Spring MVC學(xué)習(xí)教程之RequestMappingHandlerMapping匹配
- Spring MVC溫故而知新系列教程之請求映射RequestMapping注解
- Spring Mvc中傳遞參數(shù)方法之url/requestMapping詳解
- 詳解獲取Spring MVC中所有RequestMapping以及對應(yīng)方法和參數(shù)
- Spring MVC之@RequestMapping注解詳解
- Springmvc RequestMapping請求實(shí)現(xiàn)方法解析
相關(guān)文章
Kotlin與java8的SAM轉(zhuǎn)換對比(進(jìn)階)
這篇文章主要介紹了Kotlin與java8的SAM轉(zhuǎn)換對比,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05springboot 設(shè)置局域網(wǎng)訪問的實(shí)現(xiàn)步驟
Spring Boot是一個開源Java-based框架,用于創(chuàng)建獨(dú)立的、生產(chǎn)級別的Spring應(yīng)用,它旨在簡化Spring應(yīng)用的初始搭建及開發(fā)過程,通過提供各種自動配置的starter包,Spring Boot使得項(xiàng)目配置變得簡單快速,感興趣的朋友一起看看吧2024-02-02springboot如何開啟一個監(jiān)聽線程執(zhí)行任務(wù)
這篇文章主要介紹了springboot如何開啟一個監(jiān)聽線程執(zhí)行任務(wù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02springboot 項(xiàng)目使用jasypt加密數(shù)據(jù)源的方法
Jasypt 是一個 Java 庫,它允許開發(fā)者以最小的努力為他/她的項(xiàng)目添加基本的加密功能,而且不需要對密碼學(xué)的工作原理有深刻的了解。接下來通過本文給大家介紹springboot 項(xiàng)目使用jasypt加密數(shù)據(jù)源的問題,一起看看吧2021-11-11java 學(xué)習(xí)筆記(入門篇)_程序流程控制結(jié)構(gòu)和方法
程序流程控制結(jié)構(gòu)分為:順序、選擇、循環(huán)以及異常處理結(jié)構(gòu),語句是程序的基本組成單位,一般來說語句的執(zhí)行流程是按順序來進(jìn)行的,但是當(dāng)遇到一些特殊的條件,比如循環(huán),這時候語句就會按照流程控制結(jié)構(gòu)來進(jìn)行了2013-01-01