上一篇涉及的許多例如容器實例化、容器刷新等,在以前Spring源碼解析中都已講解過,再也不贅述。本節咱們來分析下 HandlerMapping 的初始化,這裏的初始化工做將對咱們以後的請求映射起到關鍵做用。java
咱們首先來看下接口 HandlerMapping ,接口只定義一個方法,經過 request 請求返回一個 HandlerExecutionChain 對象。web
public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
接着來看下 HandlerExecutionChain 裏面有哪些屬性。spring
public class HandlerExecutionChain { // 處理器對象 private final Object handler; // 攔截器數組 private HandlerInterceptor[] interceptors; public Object getHandler() { return this.handler; } // 遍歷執行攔截器 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } }
這裏以 applyPreHandle 爲例,還有 applyPostHandle、triggerAfterCompletion,分別遍歷調用攔截器的 postHandle 和 afterCompletion。跨域
咱們大體能夠分析出,HandlerMapping 就是根據請求 request,獲取到對應的請求執行鏈。準備知識事後,讓咱們來看看 HandlerMapping 的初始化邏輯:數組
public class DispatcherServlet extends FrameworkServlet { // 存放加載的 HandlerMapping實現 private List<HandlerMapping> handlerMappings; private boolean detectAllHandlerMappings = true; // 銜接上一節 @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { ...... // 關注該方法:HandlerMapping 的初始化 initHandlerMappings(context); ...... } private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; // 可指定,默認爲 true(即探測全部實現了HandlerMapping接口的 bean) if (this.detectAllHandlerMappings) { // beansOfTypeIncludingAncestors:經過 getBeansOfType獲取子容器和父容器內的 HandlerMapping // getBeansOfType會首先調用 getBeanNamesForType獲取指定類型的全部 beanName // 而後遍歷這些 beanName,使用 getBean建立實例 Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // 對於實現了 PriorityOrdered、Ordered的 HandleMapping 排序 // 若是沒有實現這倆接口,默認優先級最低 AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { // 獲取 beanName爲「handlerMapping」的 HandlerMapping HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // 若是上述處理後未找到 HandlerMapping if (this.handlerMappings == null) { // 默認策略:見 DispatcherServlet.properties(存儲了缺失的默認初始化類型) // 會註冊 BeanNameUrlHandlerMapping和 DefaultAnnotationHandlerMapping this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } } protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { // 按傳入 HandlerMapping舉例,key = org.springframework.web.servlet.HandlerMapping String key = strategyInterface.getName(); // 獲取對應的值:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, // org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping String value = defaultStrategies.getProperty(key); if (value != null) { // 根據逗號分割 String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<T>(classNames.length); for (String className : classNames) { try { Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); // 調用 createBean建立該實例 Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } ...// 省略 catch } return strategies; } else { return new LinkedList<T>(); } } }
這一步的初始化,默認的邏輯就將探測到全部 HandleMapping 類型的實例,賦值給成員變量 handlerMappings。看似好像沒有很複雜的邏輯,其實背後隱藏了不少細節。restful
這裏咱們首先要介紹一個類,ApplicationObjectSupport 。mvc
public abstract class ApplicationObjectSupport implements ApplicationContextAware { private ApplicationContext applicationContext; public final void setApplicationContext(ApplicationContext context) throws BeansException { if (context == null && !isContextRequired()) { this.applicationContext = null; this.messageSourceAccessor = null; } else if (this.applicationContext == null) { // ApplicationContext類型檢測 if (!requiredContextClass().isInstance(context)) { throw new ApplicationContextException( "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]"); } // 賦值,用於判斷是否重複初始化(及父子容器初始化,該方法也只會執行一次) this.applicationContext = context; this.messageSourceAccessor = new MessageSourceAccessor(context); // 擴展點 initApplicationContext(context); } else { // Ignore reinitialization if same context passed in. if (this.applicationContext != context) { throw new ApplicationContextException( "Cannot reinitialize with different application context: current one is [" + this.applicationContext + "], passed-in one is [" + context + "]"); } } } protected void initApplicationContext(ApplicationContext context) throws BeansException { initApplicationContext(); } /** * 被子類擴展以實現自定義的初始化邏輯 */ protected void initApplicationContext() throws BeansException { } }
咱們來分析一下 setApplicationContext 調用時機,首先該方法來自 ApplicationContextAware,該方法是在 ApplicationContextAwareProcessor.invokeAwareInterfaces 被調用。app
class ApplicationContextAwareProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException { .....// 省略 AccessControlContext的獲取 if (acc != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareInterfaces(bean); return null; } }, acc); } else { invokeAwareInterfaces(bean); } return bean; } private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) { .....// 省卻其餘一些 Aware的調用 if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } } } }
省略了一些代碼,能夠看出是在 Bean 的生命週期接口方法 BeanPostProcessor.postProcessBeforeInitialization 被調用的。cors
而 ApplicationContextAwareProcessor 的註冊就要追溯到「 容器刷新 」的 prepareBeanFactory 方法了。框架
繞了一圈,咱們發現,其實 Spring 的實現隱藏在了許多細節裏,這樣的實現讓代碼的耦合程度很是低,極易將邏輯封裝到各個模塊中。
咱們再回到以前提到的 ApplicationObjectSupport ,這個類提供了 initApplicationContext 可供子類實現定製化的邏輯。
// WebApplicationObjectSupport爲 ApplicationObjectSupport子類 public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { // 這一步主要是攔截器的相關處理 @Override protected void initApplicationContext() throws BeansException { // 空實現 extendInterceptors(this.interceptors); // 探測全部 MappedInterceptor填充 adaptedInterceptors // <mvc:interceptors>下的一個個 <mvc:interceptor>就會被封裝成 MappedInterceptor detectMappedInterceptors(this.adaptedInterceptors); initInterceptors(); } protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) { mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( getApplicationContext(), MappedInterceptor.class, true, false).values()); } }
AbstractHandlerMapping 做爲 HandlerMapping 類型的頂層抽象基類,自身實現了攔截器的初始化工做。子類劃分兩大分支:AbstractUrlHandlerMapping 和 AbstractHandlerMethodMapping。
// AbstractUrlHandlerMapping爲 AbstractHandlerMapping子類 public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping { // 默認不從父容器查找「請求處理器」 private boolean detectHandlersInAncestorContexts = false; @Override public void initApplicationContext() throws ApplicationContextException { super.initApplicationContext(); // 探測 Handler的邏輯 detectHandlers(); } protected void detectHandlers() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Looking for URL mappings in application context: " + getApplicationContext()); } // 默認只在子容器中查找,首先拿到全部註冊的 beanName String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { // 會將能做爲 Handler實例對應的 urls返回 String[] urls = determineUrlsForHandler(beanName); if (!ObjectUtils.isEmpty(urls)) { // 註冊 urls和 Handler的映射關係 registerHandler(urls, beanName); } else { if (logger.isDebugEnabled()) { logger.debug("Rejected bean name '" + beanName + "': no URL paths identified"); } } } } }
AbstractDetectingUrlHandlerMapping 以模板方法,將挑選請求處理器以抽象方法 determineUrlsForHandler 留給子類實現不一樣策略,自身經過調用父類 registerHandler 實現了處理器的註冊邏輯。
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping { protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { Assert.notNull(urlPaths, "URL path array must not be null"); for (String urlPath : urlPaths) { registerHandler(urlPath, beanName); } } protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; // 將 beanName經過 getBean轉換成單例對象 if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { resolvedHandler = getApplicationContext().getBean(handlerName); } } // handlerMap維護 url和 Handler的關聯關係 Object mappedHandler = this.handlerMap.get(urlPath); // 確保一個 url僅能對應惟一的處理器 if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { ....// 拋異常,指明一個 url只能對應一個處理器 } } else { if (urlPath.equals("/")) { if (logger.isInfoEnabled()) { logger.info("Root mapping to " + getHandlerDescription(handler)); } // 將 url爲「/」的設置根處理器 setRootHandler(resolvedHandler); } else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } // 將 url爲「/*」的設置默認處理器 setDefaultHandler(resolvedHandler); } else { // 其他的存儲關聯關係 this.handlerMap.put(urlPath, resolvedHandler); if (logger.isInfoEnabled()) { logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); } } } } }
註冊就是將 url 數組和對應的 Handler 關聯起來。那麼什麼樣的實例才能做爲 Handler 呢?接下來咱們看看不一樣子類實現 determineUrlsForHandler 是如何獲取 Handler對應的 urls。
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping { /** * beanName或 別名是以「/」開頭的. */ @Override protected String[] determineUrlsForHandler(String beanName) { List<String> urls = new ArrayList<String>(); if (beanName.startsWith("/")) { urls.add(beanName); } String[] aliases = getApplicationContext().getAliases(beanName); for (String alias : aliases) { if (alias.startsWith("/")) { urls.add(alias); } } return StringUtils.toStringArray(urls); } }
這種最爲簡單,就是把 beanName、alias 以「/」開頭的實例看成 Handler,而後 urls 就是這些實例的 beanName、alias(別名)。
@Deprecated public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandlerMapping { // 存放被 @RequestMapping標識的類,和註解的映射關係 private final Map<Class<?>, RequestMapping> cachedMappings = new HashMap<Class<?>, RequestMapping>(); /** * 這個方法會返回指定 beanName下組裝好的全部 urls * 組裝即類級別和方法級別 @RequestMapping value的組合 * 若是類未被 @Controller或 @RequestMapping標識,返回 null */ @Override protected String[] determineUrlsForHandler(String beanName) { ApplicationContext context = getApplicationContext(); // 獲取指定 beanName的 Class類型 Class<?> handlerType = context.getType(beanName); // 判斷該類是否被 @RequestMapping標識 RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class); // 這裏處理的是類級別的 @RequestMapping if (mapping != null) { this.cachedMappings.put(handlerType, mapping); Set<String> urls = new LinkedHashSet<String>(); // 獲取類級別 @RequestMapping的 value String[] typeLevelPatterns = mapping.value(); if (typeLevelPatterns.length > 0) { // 這一步會返回全部方法級別 @RequestMapping的 value全集 String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType, true); for (String typeLevelPattern : typeLevelPatterns) { // 若是定義的 url前沒有「/」,自動添加 if (!typeLevelPattern.startsWith("/")) { typeLevelPattern = "/" + typeLevelPattern; } boolean hasEmptyMethodLevelMappings = false; for (String methodLevelPattern : methodLevelPatterns) { if (methodLevelPattern == null) { hasEmptyMethodLevelMappings = true; } else { // 將類指定 url和方法指定 url拼接 String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern); addUrlsForPath(urls, combinedPattern); } } // 若是方法級別 @RequestMapping的 value爲空 或 類自己爲 Controller子類 if (hasEmptyMethodLevelMappings || org.springframework.web.servlet.mvc.Controller.class.isAssignableFrom(handlerType)) { addUrlsForPath(urls, typeLevelPattern); } } return StringUtils.toStringArray(urls); } else { // 類級別 @RequestMapping的 value爲空,直接處理方法級別 @RequestMapping return determineUrlsForHandlerMethods(handlerType, false); } } // 若是該類沒有被 @RequestMapping標識,但被 @Controller標識 else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { // 直接處理方法級別 @RequestMapping return determineUrlsForHandlerMethods(handlerType, false); } // 該類既沒被 @RequestMapping標識,也沒被 @Controller標識 else { return null; } } protected String[] determineUrlsForHandlerMethods(Class<?> handlerType, final boolean hasTypeLevelMapping) { String[] subclassResult = determineUrlsForHandlerMethods(handlerType); if (subclassResult != null) { return subclassResult; } final Set<String> urls = new LinkedHashSet<String>(); Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>(); handlerTypes.add(handlerType); handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces())); // 遍歷自身和全部父接口 for (Class<?> currentHandlerType : handlerTypes) { // 參數一:須要掃描的對象 // 參數二:回調實現,會將 currentHandlerType下的全部方法(以及父類),傳入 doWith處理 // 參數三:過濾匹配規則的方法。過濾掉橋接方法以及 Object類下的全部方法 ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) { // 全部被 @RequestMapping接口標記的方法 RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (mapping != null) { // 獲取 @RequestMapping的 value String[] mappedPatterns = mapping.value(); if (mappedPatterns.length > 0) { // 遍歷 value數組 for (String mappedPattern : mappedPatterns) { // 沒有類級別 @RequestMapping,且方法指定的 url沒有以「/」開頭,默認加上 if (!hasTypeLevelMapping && !mappedPattern.startsWith("/")) { mappedPattern = "/" + mappedPattern; } // 放入 url列表 addUrlsForPath(urls, mappedPattern); } } else if (hasTypeLevelMapping) { // 若是方法 @RequestMapping的 value爲空 urls.add(null); } } } }, ReflectionUtils.USER_DECLARED_METHODS); } return StringUtils.toStringArray(urls); } protected void addUrlsForPath(Set<String> urls, String path) { urls.add(path); if (this.useDefaultSuffixPattern && path.indexOf('.') == -1 && !path.endsWith("/")) { urls.add(path + ".*"); urls.add(path + "/"); } } }
這是 Spring 3.2 版本以前對於註解標識 Handler的支持類。從上面的源碼,咱們能夠看出,處理是區分類級別註解、方法級別註解,在類上聲明的註解屬性將做用於該類全部的接口方法(最後會調用方法將二者合併)。最後 determineUrlsForHandler 返回的將會是組裝好的 url 全集。
如今這個類已被標識廢棄,代替者爲 RequestMappingHandlerMapping。在瞭解它以前,咱們須要瞭解另外一分支,也是 RequestMappingHandlerMapping 的抽象父類。
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { private boolean detectHandlerMethodsInAncestorContexts = false; // 內部類,用於註冊 url和 HandlerMethod的映射關係 private final MappingRegistry mappingRegistry = new MappingRegistry(); @Override public void afterPropertiesSet() { initHandlerMethods(); } protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } // 獲取子容器中全部 Object類型的 beanName // detectHandlerMethodsInAncestorContexts默認爲 false,即只探測子容器(mvc) String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); // 遍歷註冊的 beanName for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = getApplicationContext().getType(beanName); } catch (Throwable ex) { // 對於沒法解析的類型,會忽略 if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } // isHandler由不一樣策略的子類實現 if (beanType != null && isHandler(beanType)) { // 會探測知足類型的 Handler下的全部方法 detectHandlerMethods(beanName); } } } // 空實現:子類可擴展 handlerMethodsInitialized(getHandlerMethods()); } protected void detectHandlerMethods(final Object handler) { // 獲取 Handler類型 Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); // 獲取本來的類型,以防個別會被 Ciglib加強代理 final Class<?> userType = ClassUtils.getUserClass(handlerType); // MethodIntrospector.selectMethods幾乎是對上面 // DefaultAnnotationHandlerMapping.determineUrlsForHandlerMethods的封裝 // 這裏不作展開講解,大體作的就是把 @RequestMapping標識的方法找出來 // key-就是符合要求的方法,value-@RequestMapping的屬性封裝的 RequestMappingInfo對象 Map<Method, T> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<T>() { @Override public T inspect(Method method) { try { // 子類實現 return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } } }); if (logger.isDebugEnabled()) { logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods); } for (Map.Entry<Method, T> entry : methods.entrySet()) { // 挑選一個可調用的方法 Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); T mapping = entry.getValue(); // 註冊 HandlerMethod registerHandlerMethod(handler, invocableMethod, mapping); } } protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } class MappingRegistry { // 存放 RequestMappingInfo和 MappingRegistration映射關係 private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>(); // 存放 RequestMappingInfo和 HandlerMethod映射關係 // 校驗以防止同一個 RequestMappingInfo對應多個 HandlerMethod private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>(); // 存放直接 private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>(); // private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<String, List<HandlerMethod>>(); // 存放 HandlerMethod和跨域註解 @CrossOrigin配置的映射關係 private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<HandlerMethod, CorsConfiguration>(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { // 使用 Handler和 Method封裝成 HandlerMethod HandlerMethod handlerMethod = createHandlerMethod(handler, method); // mappingLookup的校驗,目的見註釋↑ assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } // 存儲 RequestMappingInfo和 handlerMethod映射關係 this.mappingLookup.put(mapping, handlerMethod); // 篩選出不帶通配符(例如 "/*" or "/?")的 url放入 urlLookup // urlLookup爲 MultiValueMap類型,即 Map<String,List<T>> // key:@RequestMapping指定的不帶通配符的屬性"value",value:List<RequestMappingInfo> // 這種一對多的結構是預防,會有多個方法對應相同的請求路徑(好比 restful風格的接口) List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { this.urlLookup.add(url, mapping); } String name = null; // 默認使用 RequestMappingInfoHandlerMethodMappingNamingStrategy if (getNamingStrategy() != null) { // 若是 mapping未指定 name,則使用 類名中的大寫字母組合#方法名 // 例如:UserController.test() ——> UC#test() name = getNamingStrategy().getName(handlerMethod, mapping); // 放入 nameLookup addMappingName(name, handlerMethod); } // @CrossOrigin支持,用於支持請求跨域 CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } // 放入 registry this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } } } }
從該分支抽象類的命名也可以看出,這個分支將具體的處理器 handler 和 具體調用的方法 method 封裝成了 HandlerMethod 類型對象,不少映射關係都跟該對象有關。
與另外一個分支不一樣的是,該分支不是經過重寫 initApplicationContext 來探測處理器的,它依舊沿用了父類該方法的邏輯去初始化「攔截器」,但探測處理器(Handler)則是利用了另外一個生命週期接口 InitializingBean.afterPropertiesSet。該方法在 bean 的初始化邏輯中被調用。(見 實例建立(下)invokeInitMethods 方法)
接下來來看看 RequestMappingHandlerMapping 是如何實現 isHandler 和 getMappingForMethod,來判斷哪些才實例能做爲 Handler ,以及對 RequestMappingInfo 的封裝。
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware { @Override protected boolean isHandler(Class<?> beanType) { // 被 @Controller或 @RequestMapping標識的類 return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } /** * 若是方法被標識 @RequestMapping,則封裝成 RequestMappingInfo * 若是方法未被標識 @RequestMapping,則返回 null */ @Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { // 用方法上的 @RequestMapping屬性值封裝 RequestMappingInfo RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { // 用類上的 @RequestMapping屬性值封裝 RequestMappingInfo RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { // 將類級別和方法級別的結合,返回新的 RequestMappingInfo // 這裏能夠看出類級別的適用於該類下全部的方法 info = typeInfo.combine(info); } } return info; } private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element)); // 若是方法未被標識 @RequestMapping,則返回 null return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null); } protected RequestMappingInfo createRequestMappingInfo( RequestMapping requestMapping, RequestCondition<?> customCondition) { // 用方法上的 @RequestMapping屬性值封裝 RequestMappingInfo return RequestMappingInfo .paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) .methods(requestMapping.method()) .params(requestMapping.params()) .headers(requestMapping.headers()) .consumes(requestMapping.consumes()) .produces(requestMapping.produces()) .mappingName(requestMapping.name()) .customCondition(customCondition) .options(this.config) .build(); } }
RequestMappingHandlerMapping 做爲 DefaultAnnotationHandlerMapping (廢棄)的替代者,斷定標準依然是 @Controller 或 @RequestMapping,講到這裏,你們應該就明白咱們平時使用的這兩個註解到底是怎樣被框架所識別了。
經過對兩個分支的梳理,應該能清楚的看到 SpringMVC 初始化映射關係的時機,以及具體都作了哪些邏輯處理。正是這裏將請求的 url 和真正被調用的 Handler創建起了聯繫,以後的請求就能正確的找處處理器(Handler)。