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

通过类图可以看到,同样是继承父类 AbstractHandlerMapping来进行拦截器的初始化工作,实际上处理自己逻辑的只有下面三个类;
需要注意的是RequestMappingHandlerMapping初始化并不是重写initApplicationContext()方法 ,而是通过实现InitializingBean接口来进行初始工作的。 备注:InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是实现该接口的类,在初始化bean的时候会执行该方法。
来看AbstractHandlerMethodMapping 中关键的代码:
     public void afterPropertiesSet() { //实现了InitializingBean接口的方法,进行初始化的入口。
this.initHandlerMethods();
} protected void initHandlerMethods() {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
}
     //扫描应用下所有Object类
String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class) : this.getApplicationContext().getBeanNamesForType(Object.class);
String[] arr$ = beanNames;
int len$ = beanNames.length; for(int i$ = ; i$ < len$; ++i$) {
String beanName = arr$[i$];
if (this.isHandler(this.getApplicationContext().getType(beanName))) { //ishandler由子类实现,是个钩子方法,让子类实现自己的逻辑
this.detectHandlerMethods(beanName);
}
} this.handlerMethodsInitialized(this.getHandlerMethods());//初始化处理器对象,目前是钩子方法,但是也没有子类实现这个方法
}

isHandler方法是在RequestMappingHandlerMapping中实现的

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

回到AbstractHandlerMethodMapping看:

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

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

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

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

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

 public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
//这块实际上是两个map保存的,泛型实际上就是RequestMappingInfo,这个就是匹配条件 HanlderMethod是封装了处理器全部信息的封装类
     private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap(); //存的是 key:匹配条件 value: 处理器
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
     protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod handlerMethod;
if (handler instanceof String) {
String beanName = (String)handler;
handlerMethod = new HandlerMethod(beanName, this.getApplicationContext(), method);
} else {
handlerMethod = new HandlerMethod(handler, method);
} HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(handlerMethod)) { //不允许存在一个mapping对应多个handlerMethod
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.");
} else {
this.handlerMethods.put(mapping, handlerMethod); //存放第一个映射集合
if (this.logger.isInfoEnabled()) {
this.logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
} Set<String> patterns = this.getMappingPathPatterns(mapping); //获取方法的URL
Iterator i$ = patterns.iterator(); while(i$.hasNext()) {
String pattern = (String)i$.next();
if (!this.getPathMatcher().isPattern(pattern)) { //依次放入第二个映射集合
this.urlMap.add(pattern, mapping);
}
} }
}

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

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

欢迎探讨

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

  1. Spring MVC的handlermapping之SimpleUrlHandlerMapping初始化

    前面信息同BeanNameUrlHandlerMapping,这里不再过多分析,详情请看 :Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化 ...

  2. Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化

    先介绍一下: BeanNameUrlHandlerMapping是基于配置文件的方式; 所有处理器需要在XML文件中,以Bean的形式配置. 缺点:配置繁琐; 如果多个URL对应同一个处理器,那么需要 ...

  3. Spring MVC 梳理 - handlerMapping和handlerAdapter分析

    参考图片 综上所述我们来猜测一下spring mvc 中根据URL找到处理器Controller中相应方法的流程 ①:获取Request的URL ②:从UrlLookup这个map中找到相应的requ ...

  4. spring mvc 自定义Handlermapping

    上次大概写了个可以解决velocity 多视图的东西. 但是实际运用过程中又到处找了些资料看了下.这里 小计下: DispatcherServlet解析过程: ..1..HandlerMapping. ...

  5. Spring MVC的handlermapping之请求分发如何找到正确的Handler(BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping)

    本文讲的是Spring MVC如何找到正确的handler, 前面请求具体怎么进入到下面的方法,不再细说. 大概就是Spring mvc通过servlet拦截请求,实现doService方法,然后进入 ...

  6. spring mvc(4) HandlerMapping

    在前面一节里提到,DispatcherServlet在接收到请求后,通过HandlerMapping找到处理请求对应的Controller(其实处理请求器并不一定是Controller,还可以是Htt ...

  7. Spring MVC:HandlerMapping

    HandlerMapping 的类图 Spring中存在两种类型的handlers.第一种是 handler mappings(处理程序映射).它们的角色定位与前面所描述的功能完全相同.它们尝试将当前 ...

  8. Spring MVC 上下文(ApplicationContext)初始化入口

    Spring 常用上下文容器有哪些 ApplicationContext ClassPathXmlApplicationContext ApplicationContext context = new ...

  9. Spring MVC的handlermapping之请求分发如何找到正确的Handler(RequestMappingHandlerMapping)

    这个思路同样是通过在AbstractHandlerMethodMapping里面来实现getHandlerInternal()实现自己的方法来处理寻找正确的处理器,不懂得请看上一篇. protecte ...

随机推荐

  1. 【mongodb系统学习之三】进入mongodb shell

    三. 进入mongodb shell(数据库操作界面) : 1).在mongodb的bin目录下输入./mongo,默认连接test数据库,连接成功会显示数据库版本和当前连接的数据库名,如图: 2). ...

  2. Flex父子窗口相互调用

    Flex父子窗口相互调用 1.设计思路 (1)子窗口调用父窗口的方法 (2)子窗口做了修改后,返回父窗口,父窗口调用子窗口函数 2.设计源码 (1)父窗口 ParentWindow.mxml: < ...

  3. 获取Filter的三种途径

    一.通过CLSID [cpp] view plaincopyprint? IBaseFilter *pF = 0; HRESULT hr = CoCreateInstance(clsid, 0, CL ...

  4. 使用 github 做代码管理,知道这些就够了

    只要掌握了下面的常用命令,基本上用使用 github 就没有问题.github 有两种认证方式,一种是通过 ssh 私钥的方式,一种通过 https 的账号名和密码.ssh 方式需要创建本地秘钥并且添 ...

  5. View的平移、缩放、旋转以及位置、坐标系

    原创 2015年05月12日 13:15:29 标签: Android / Scroll / Scale / Translation / Rotation 24733 Android开发中,经常会接触 ...

  6. [BZOJ2743] [HEOI2012] 采花 (树状数组)

    Description 萧芸斓是Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了n朵花,花有c种颜色(用整数1-c表示),且花是排成一 ...

  7. XAMPP搭建PHP

    在学习一些前后端交互时,经常会有跟PHP作为后端(服务器)的交互,不能将php文件放在本地进行请求,必须将PHP运行在Apache环境中.但是对一些新手来说,学习搭建一个Apache环境也并非易事,所 ...

  8. js改变盒子大小(上下左右)分析

    js改变盒子大小 知识点 三个mouse事件:mousedown mousemove mouseup css的定位和cursor 思路 先解决单边问题识别范围,得到所选区域 event. 根据距离,判 ...

  9. Java高并发秒杀系统【观后总结】

    项目简介 在慕课网上发现了一个JavaWeb项目,内容讲的是高并发秒杀,觉得挺有意思的,就进去学习了一番. 记录在该项目中学到了什么玩意.. 该项目源码对应的gitHub地址(由观看其视频的人编写,并 ...

  10. ps智能对象