Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

须知少年凌云志,曾许人间第一流。这篇文章主要讲述Spring MVC的handlermapping之RequestMappingHandlerMapping初始化相关的知识,希望能为你提供帮助。

RequestMappingHandlerMapping:这个handlerMapping是基于注解的
同样,先上类图:

Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

文章图片

通过类图可以看到,同样是继承父类  AbstractHandlerMapping来进行拦截器的初始化工作,实际上处理自己逻辑的只有下面三个类;
需要注意的是RequestMappingHandlerMapping初始化并不是重写initApplicationContext()方法  ,而是通过实现InitializingBean接口来进行初始工作的。

备注:InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是实现该接口的类,在初始化bean的时候会执行该方法。
来看AbstractHandlerMethodMapping  中关键的代码:

1public void afterPropertiesSet() { //实现了InitializingBean接口的方法,进行初始化的入口。 2this.initHandlerMethods(); 3} 4 5protected void initHandlerMethods() { 6if (this.logger.isDebugEnabled()) { 7this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext()); 8} 9//扫描应用下所有Object类 10String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class) : this.getApplicationContext().getBeanNamesForType(Object.class); 11String[] arr$ = beanNames; 12int len$ = beanNames.length; 13 14for(int i$ = 0; i$ < len$; ++i$) { 15String beanName = arr$[i$]; 16if (this.isHandler(this.getApplicationContext().getType(beanName))) { //ishandler由子类实现,是个钩子方法,让子类实现自己的逻辑 17this.detectHandlerMethods(beanName); 18} 19} 20 21this.handlerMethodsInitialized(this.getHandlerMethods()); //初始化处理器对象,目前是钩子方法,但是也没有子类实现这个方法 22}

isHandler方法是在RequestMappingHandlerMapping中实现的
1protected boolean isHandler(Class< ?> beanType) { //非常简单, 就是看这个类有没有Controller或者RequestMapping注解,有一个就行 2return AnnotationUtils.findAnnotation(beanType, Controller.class) != null || AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null; 3}

回到AbstractHandlerMethodMapping看:
1protected void detectHandlerMethods(Object handler) { //开始注册handler 2Class< ?> handlerType = handler instanceof String ? this.getApplicationContext().getType((String)handler) : handler.getClass(); 3final Class< ?> userType = ClassUtils.getUserClass(handlerType);
//这块是获取handelr的所有方法,但是有一个过滤器,就是把有匹配条件的的method获取到 4Set< Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { 5public boolean matches(Method method) { 6return AbstractHandlerMethodMapping.this.getMappingForMethod(method, userType) != null; //getMappingForMethod钩子方法,子类实现 7} 8}); 9Iterator i$ = methods.iterator(); 10//遍历method 进行注册。 11while(i$.hasNext()) { 12Method method = (Method)i$.next(); 13T mapping = this.getMappingForMethod(method, userType); 14this.registerHandlerMethod(handler, method, mapping); 15} 16 17}

来看getMappingForMethod的实现,是在RequestMappingHandlerMapping实现的
1protected RequestMappingInfo getMappingForMethod(Method method, Class< ?> handlerType) { 2RequestMappingInfo info = null; //获取方法上的RequestMapping注解信息 3RequestMapping methodAnnotation = (RequestMapping)AnnotationUtils.findAnnotation(method, RequestMapping.class); 4if (methodAnnotation != null) { 5RequestCondition< ?> methodCondition = this.getCustomMethodCondition(method); 6info = this.createRequestMappingInfo(methodAnnotation, methodCondition); 构造匹配条件
// 获取类上的面RequestHandlerMapping注解信息 7RequestMapping typeAnnotation = (RequestMapping)AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); 8if (typeAnnotation != null) { 9RequestCondition< ?> typeCondition = this.getCustomTypeCondition(handlerType); 10info = this.createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); 构造匹配条件,同方法的进行合并 11} 12} 13 14return info; 15}

备注下; RequestMappingInfo 实际上是匹配条件的一个抽象对象,包含了url,method,param,header...等等
来看注册方法前,先看一下处理器是保存在哪的;
1 public abstract class AbstractHandlerMethodMapping< T> extends AbstractHandlerMapping implements InitializingBean { 2//这块实际上是两个map保存的,泛型实际上就是RequestMappingInfo,这个就是匹配条件 HanlderMethod是封装了处理器全部信息的封装类

3private final Map< T, HandlerMethod> handlerMethods = new LinkedHashMap(); //存的是 key:匹配条件 value: 处理器 4private final MultiValueMap< String, T> urlMap = new LinkedMultiValueMap(); //key: url value: 匹配条件

这块讲一下MultiValueMap
public interface MultiValueMap< K, V> extends Map< K, List< V> > //实际上就是个 value是个list的map

1protected void registerHandlerMethod(Object handler, Method method, T mapping) { 2HandlerMethod handlerMethod; 3if (handler instanceof String) { 4String beanName = (String)handler; 5handlerMethod = new HandlerMethod(beanName, this.getApplicationContext(), method); 6} else { 7handlerMethod = new HandlerMethod(handler, method); 8} 9 10HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping); 11if (oldHandlerMethod != null & & !oldHandlerMethod.equals(handlerMethod)) { //不允许存在一个mapping对应多个handlerMethod 12throw new IllegalStateException("Ambiguous mapping found. Cannot map \'" + handlerMethod.getBean() + "\' bean method \\n" + handlerMethod + "\\nto " + mapping + ": There is already \'" + oldHandlerMethod.getBean() + "\' bean method\\n" + oldHandlerMethod + " mapped."); 13} else { 14this.handlerMethods.put(mapping, handlerMethod); //存放第一个映射集合 15if (this.logger.isInfoEnabled()) { 16this.logger.info("Mapped \\"" + mapping + "\\" onto " + handlerMethod); 17} 18 19Set< String> patterns = this.getMappingPathPatterns(mapping); //获取方法的URL 20Iterator i$ = patterns.iterator(); 21 22while(i$.hasNext()) { 23String pattern = (String)i$.next(); 24if (!this.getPathMatcher().isPattern(pattern)) { //依次放入第二个映射集合 25this.urlMap.add(pattern, mapping); 26} 27} 28 29} 30}

到此为止,RequestMappingHandlerMapping就初始化完成了。
疑问:   为什么非注解映射器都是通过重写initApplication方法,而注解映射器是通过实现iniliazingBean接口来初始化,这样的好处是什么?
【Spring MVC的handlermapping之RequestMappingHandlerMapping初始化】欢迎探讨

    推荐阅读