Spring MVC的handlermapping之RequestMappingHandlerMapping初始化
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初始化的更多相关文章
- Spring MVC的handlermapping之SimpleUrlHandlerMapping初始化
前面信息同BeanNameUrlHandlerMapping,这里不再过多分析,详情请看 :Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化 ...
- Spring MVC的handlermapping之BeanNameUrlHandlerMapping初始化
先介绍一下: BeanNameUrlHandlerMapping是基于配置文件的方式; 所有处理器需要在XML文件中,以Bean的形式配置. 缺点:配置繁琐; 如果多个URL对应同一个处理器,那么需要 ...
- Spring MVC 梳理 - handlerMapping和handlerAdapter分析
参考图片 综上所述我们来猜测一下spring mvc 中根据URL找到处理器Controller中相应方法的流程 ①:获取Request的URL ②:从UrlLookup这个map中找到相应的requ ...
- spring mvc 自定义Handlermapping
上次大概写了个可以解决velocity 多视图的东西. 但是实际运用过程中又到处找了些资料看了下.这里 小计下: DispatcherServlet解析过程: ..1..HandlerMapping. ...
- Spring MVC的handlermapping之请求分发如何找到正确的Handler(BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping)
本文讲的是Spring MVC如何找到正确的handler, 前面请求具体怎么进入到下面的方法,不再细说. 大概就是Spring mvc通过servlet拦截请求,实现doService方法,然后进入 ...
- spring mvc(4) HandlerMapping
在前面一节里提到,DispatcherServlet在接收到请求后,通过HandlerMapping找到处理请求对应的Controller(其实处理请求器并不一定是Controller,还可以是Htt ...
- Spring MVC:HandlerMapping
HandlerMapping 的类图 Spring中存在两种类型的handlers.第一种是 handler mappings(处理程序映射).它们的角色定位与前面所描述的功能完全相同.它们尝试将当前 ...
- Spring MVC 上下文(ApplicationContext)初始化入口
Spring 常用上下文容器有哪些 ApplicationContext ClassPathXmlApplicationContext ApplicationContext context = new ...
- Spring MVC的handlermapping之请求分发如何找到正确的Handler(RequestMappingHandlerMapping)
这个思路同样是通过在AbstractHandlerMethodMapping里面来实现getHandlerInternal()实现自己的方法来处理寻找正确的处理器,不懂得请看上一篇. protecte ...
随机推荐
- Windows 7 Visual Studio 2008配置OpenGL开发环境
Windows 7 Visual Studio 2008配置OpenGL开发环境 glut下载地址: http://www.opengl.org/resources/libraries/glut/gl ...
- Linux显示目前与过去登入系统的用户相关信息
Linux显示目前与过去登入系统的用户相关信息 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ last youhaido pts/0 :0 Sat Jan 2 ...
- 芝麻HTTP:PhantomJS的安装
PhantomJS是一个无界面的.可脚本编程的WebKit浏览器引擎,它原生支持多种Web标准:DOM操作.CSS选择器.JSON.Canvas以及SVG. Selenium支持PhantomJS,这 ...
- jQuery.extend 函数使用详解
JQuery的extend扩展方法: Jquery的扩展方法extend是我们在写插件的过程中常用的方法,该方法有一些重载原型,在此,我们一起去了解了解. 一.Jquery的扩展方 ...
- freemarker中的round、floor和ceiling数字的舍入处理(十七)
1.简易说明 (1)round:四舍五入 (2)floor:向下取整 (3)ceiling:向上取整 2.举例说明 <#--freemarker中的round.floor和ceiling数字的舍 ...
- jsp学习笔记之:4种基本语法
一. jsp注释:<%-- js注释 --%> 二. jsp声明: <%! public int count; public String test(){return "j ...
- canvas练手项目(二)——各种操作基础
想想应该在canvas上面作画了,那么就不得不提到事件了. (打着canvas的旗号,写着mouse事件.挂羊头卖狗肉!哈哈哈哈哈~) 先来看一看HTML事件属性,我们要用的就是Mouse事件,就先研 ...
- c#抽取pdf文档标题(2)
public class IETitle { public static List<WordInfo> WordsInfo = new List<WordInfo>(); pr ...
- 洛谷 P1146 【硬币翻转】题解
很久很久之前做过的一道题 翻n-1枚硬币,就是有一枚不翻,也可以理解为翻一枚 直接上程序,看程序说话 #include<iostream> using namespace std; ; b ...
- elfinder源码浏览-Volume文件系统操作类(1)
今天看了一个文件管理的java后台源码,elfinder 发现这个东东比我写的代码效率告到不知道哪去了,苦思冥想后还是抽点时间看看吧.. 它实现了我们电脑上的所以关于文件操作的动作,并生成了api开放 ...