上一篇涉及的许多例如容器实例化、容器刷新等,在以前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)。