Spring MVC的handlermapping之RequestMappingHandlerMapping初始化

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

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

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

isHandler方法是在RequestMappingHandlerMapping中实现的

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

回到AbstractHandlerMethodMapping看:

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

来看getMappingForMethod的实现,是在RequestMappingHandlerMapping实现的

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

备注下;RequestMappingInfo 实际上是匹配条件的一个抽象对象,包含了url,method,param,header...等等

来看注册方法前,先看一下处理器是保存在哪的;

1 public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
2     //这块实际上是两个map保存的,泛型实际上就是RequestMappingInfo,这个就是匹配条件 HanlderMethod是封装了处理器全部信息的封装类
3     private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap(); //存的是 key:匹配条件 value: 处理器
4     private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap(); //key: url value: 匹配条件

这块讲一下MultiValueMap

public interface MultiValueMap<K, V> extends Map<K, List<V>> //实际上就是个 value是个list的map
 1     protected void registerHandlerMethod(Object handler, Method method, T mapping) {
 2         HandlerMethod handlerMethod;
 3         if (handler instanceof String) {
 4             String beanName = (String)handler;
 5             handlerMethod = new HandlerMethod(beanName, this.getApplicationContext(), method);
 6         } else {
 7             handlerMethod = new HandlerMethod(handler, method);
 8         }
 9
10         HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping);
11         if (oldHandlerMethod != null && !oldHandlerMethod.equals(handlerMethod)) { //不允许存在一个mapping对应多个handlerMethod
12             throw 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 {
14             this.handlerMethods.put(mapping, handlerMethod); //存放第一个映射集合
15             if (this.logger.isInfoEnabled()) {
16                 this.logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
17             }
18
19             Set<String> patterns = this.getMappingPathPatterns(mapping); //获取方法的URL
20             Iterator i$ = patterns.iterator();
21
22             while(i$.hasNext()) {
23                 String pattern = (String)i$.next();
24                 if (!this.getPathMatcher().isPattern(pattern)) { //依次放入第二个映射集合
25                     this.urlMap.add(pattern, mapping);
26                 }
27             }
28
29         }
30     }

到此为止,RequestMappingHandlerMapping就初始化完成了。

疑问:  为什么非注解映射器都是通过重写initApplication方法,而注解映射器是通过实现iniliazingBean接口来初始化,这样的好处是什么?

欢迎探讨

原文地址:https://www.cnblogs.com/haoerlv/p/8668635.html

时间: 2024-10-10 19:26:56

Spring MVC的handlermapping之RequestMappingHandlerMapping初始化的相关文章

Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化

先介绍一下: BeanNameUrlHandlerMapping是基于配置文件的方式; 所有处理器需要在XML文件中,以Bean的形式配置. 缺点:配置繁琐; 如果多个URL对应同一个处理器,那么需要配置多条,同时也会实例化多个对象等等... 因为springmvc 是基于spring的,所以他的初始化肯定是在spring容器初始化之后才进行的. 先上类图: 可以看到BeanNameUrlHandlerMapping父类最终实现了ApplicationContextAware接口,所以Sprin

Spring MVC之HandlerMapping初始化

Spring MVC的Control主要由HandlerMapping和HandlerAdapter两个组件提供. HandlerMapping负责映射用户的URL和对应的处理类,HandlerMapping并没有规定这个URL与应用的处理类如何映射,在HandlerMapping接口中只定义了根据一个URL必须返回一个由HandlerExecutionChain代表的处理链,我们可以在这个处理链中添加任意的HandlerAdapter实例来处理这个URL的对应的请求. HandlerMappi

Spring MVC 梳理 - handlerMapping和handlerAdapter分析

参考图片 综上所述我们来猜测一下spring mvc 中根据URL找到处理器Controller中相应方法的流程 ①:获取Request的URL ②:从UrlLookup这个map中找到相应的requestMappingInfo ③:如果没找到则遍历所有requestMappingInfo的信息直到找到匹配的requestMappingInfo ④:根据requestMappingInfo到mappingLookup中找到handlerMethod Spring mvc是如何通过URL查找到对应

Spring MVC:handlermapping

HandlerMapping 首先这是一个接口,也就是可扩展.它的作用就是根据不同的请求去匹配对应的Handler,也就是根据请求匹配一个请求处理器.这个过程需要两个步骤:第一步,需要将Handler注册到HandlerMapping中:第二步,分析请求根据规则从已注册的Handler中匹配到对应的Handler,即Controller.默认情况下,SpringMvc为我们提供了几个默认的HandlerMapping的实现,通过优先级的次序决定执行的顺序. HandlerMapping执行顺序

Spring MVC DispatcherServlet的启动以及初始化

Spring MVC是一个MVC模式的实现,在使用Spring MVC 时,主要需要在web.xml配置文件中设置DispatcherServlet,这个Servlet是实现Spring mvc 的前端控制器,所有的Web请求都需要通过它来处理,进行匹配.转发.数据处理.DispatcherServlet是实现Spring MVC最核心的部分. 在使用SpringMVC 时我们通常需要如下配置: <servlet> <servlet-name>mvc-dispatcher</

Spring学习总结(2.3)-Spring MVC:handlermapping

上篇博客讲了DispathcerServlet的流转过程以及它是如何工作的,从这篇博客开始就开始深入到DispatcherServlet的内部看看它的几个主要的组件.那么这一篇就从HandlerMapping这个组件开始学习. HandlerMapping 首先这是一个接口,也就是可扩展.它的作用就是根据不同的请求去匹配对应的Handler,也就是根据请求匹配一个请求处理器.这个过程需要两个步骤:第一步,需要将Handler注册到HandlerMapping中:第二步,分析请求根据规则从已注册的

spring mvc 关键接口 HandlerMapping HandlerAdapter

HandlerMapping Spring mvc 使用HandlerMapping来找到并保存url请求和处理函数间的mapping关系.   以DefaultAnnotationHandlerMapping为例来具体看HandlerMapping的作用   DefaultAnnotationHandlerMapping将扫描当前所有已经注册的spring beans中的@requestmapping标注以找出url 和 handler method处理函数的关系并予以关联. Handlera

Spring MVC 学习笔记 handlerMapping和handlerAdapter

HandlerMapping Spring mvc 使用HandlerMapping来找到并保存url请求和处理函数间的mapping关系.   以DefaultAnnotationHandlerMapping为例来具体看HandlerMapping的作用   DefaultAnnotationHandlerMapping将扫描当前所有已经注册的spring beans中的@requestmapping标注以找出url 和 handler method处理函数的关系并予以关联. Handlera

Spring mvc之源码 handlerMapping和handlerAdapter分析

Spring mvc之源码 handlerMapping和handlerAdapter分析 本篇并不是具体分析Spring mvc,所以好多细节都是一笔带过,主要是带大家梳理一下整个Spring mvc的执行流程,以及如何根据URL查找处理器Controller的实现 (适合那些刚阅读源码不知道如何下手的人) http://www.guojinbao.com/borrow/borrowDetail/GETadLPjnf0[d].do 如何根据URL地址---->找到正确处理器Controller