Spring MVC 解读——<mvc:annotation-driven/>
Spring MVC 解读——<mvc:annotation-driven/>
一、AnnotationDrivenBeanDefinitionParser
通常如果我们希望通过注解的方式来进行Spring MVC开发,我们都会在***-servlet.xml中加入<mvc:annotation-driven/>标签来告诉Spring我们的目的。但是我们为什么这么做呢?这个标签是什么意思呢?它做了什么呢?
同样为了弄清楚这些问题, 像<context:component-scan/>标签一样,我们先找到它的解析类。第一篇文章中说过了,所有的自定义命名空间(像mvc,context等)下的标签解析都是由BeanDefinitionParser接口的子类来完成的。参看第一篇文章中的图片
我们看到有多个AnnotationDrivenBeanDefinitionParser,他们是用来处理不同命名空间下的<annotation-driven/>标签的,我们今天研究的是<mvc:annotation-driven/>标签,所以我们找到对应的实现类是org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser。
通过阅读类注释文档,我们发现这个类主要是用来向工厂中注册了
RequestMappingHandlerMapping
BeanNameUrlHandlerMapping
RequestMappingHandlerAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
上面几个Bean实例。这几个类都是用来做什么的呢?
前两个是HandlerMapping接口的实现类,用来处理请求映射的。其中第一个是处理@RequestMapping注解的。第二个会将controller类的名字映射为请求url。
中间三个是用来处理请求的。具体点说就是确定调用哪个controller的哪个方法来处理当前请求。第一个处理@Controller注解的处理器,支持自定义方法参数和返回值(很酷)。第二个是处理继承HttpRequestHandler的处理器。第三个处理继承自Controller接口的处理器。
后面三个是用来处理异常的解析器。
二、实现
光说无凭据,我们直接看代码:
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
//第一个在这 RequestMappingHandlerMapping
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", false);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
String methodMappingName = parserContext.getReaderContext().registerWithGeneratedName(handlerMappingDef);
//第二个在这 RequestMappingHandlerAdapter
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
handlerAdapterDef.setSource(source);
handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
if (argumentResolvers != null) {
handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
if (asyncTimeout != null) {
handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
}
if (asyncExecutor != null) {
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
}
handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
//异常处理解析器
RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
exceptionHandlerExceptionResolver.setSource(source);
exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
String methodExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
//异常处理解析器
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
responseStatusExceptionResolver.getPropertyValues().add("order", 1);
String responseStatusExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(responseStatusExceptionResolver);
//异常处理解析器
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(defaultExceptionResolver);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, methodMappingName));
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, handlerAdapterName));
parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
//这里注册了BeanNameUrlHandlerMapping,SimpleControllerHandlerAdapter等
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
parserContext.popAndRegisterContainingComponent();
return null;
}
//在这啊。
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
registerBeanNameUrlHandlerMapping(parserContext, source);
registerHttpRequestHandlerAdapter(parserContext, source);
registerSimpleControllerHandlerAdapter(parserContext, source);
}
略长,但很容易看明白的代码。看注释我们发现,它的确注册了上面说的那几个类。
三、总结
我们知道了它们自动为我们注册了这么多的Bean,那这些Bean是做什么的呢?
我们主要说明里面的两个,RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
第一个是HandlerMapping的实现类,它会处理@RequestMapping 注解,并将其注册到请求映射表中。(下片文章我们会详细介绍的)
第二个是HandlerAdapter的实现类,它是处理请求的适配器,说白了,就是确定调用哪个类的哪个方法,并且构造方法参数,返回值。(后面文章也会陆续详细介绍的)
那么它跟<context:component-scan/>有什么区别呢?其实想上篇文章中介绍的,<context:component-scan/>标签是告诉Spring 来扫描指定包下的类,并注册被@Component,@Controller,@Service,@Repository等注解标记的组件。
而<mvc:annotation-driven/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。
本文转自:https://my.oschina.net/HeliosFly/blog/205343
Spring MVC 解读——<mvc:annotation-driven/>的更多相关文章
- Spring MVC 解读——<context:component-scan/>
转自:http://my.oschina.net/HeliosFly/blog/203149 作者:GoodLoser. Spring MVC 解读---<context:component-s ...
- Spring MVC 解读——<mvc:annotation-driven/>(转)
转自:http://my.oschina.net/HeliosFly/blog/205343 Spring MVC 解读——<mvc:annotation-driven/> 一.Annot ...
- Spring MVC 解读——@RequestMapping (1)(转)
转自:http://my.oschina.net/HeliosFly/blog/212329 Spring MVC 解读——@RequestMapping 为了降低文章篇幅,使得文章更目标化,简洁化, ...
- Spring MVC 解读——@Autowired(转)
转自:http://my.oschina.net/HeliosFly/blog/203902 Spring MVC 解读——@Autowired 一.@Autowired 作为一个Spring开发者对 ...
- Spring MVC 解读——@Autowired、@Controller、@Service从原理层面来分析
目录(?)[+] Spring MVC 解读Autowired 一Autowired 二BeanPostProcessor 三磨刀砍柴 四Bean 工厂 五实例化与装配 六执行装配 七一切的开始 ...
- Spring MVC 解读——@RequestMapping (2)(转)
转自:http://my.oschina.net/HeliosFly/blog/214438 Spring MVC 解读——@RequestMapping 上一篇文章中我们了解了Spring如何处理@ ...
- 【转】Spring MVC 解读——<mvc:annotation-driven/>
转载自:http://my.oschina.net/HeliosFly/blog/205343 一.AnnotationDrivenBeanDefinitionParser 通常如果我们希望通过注解的 ...
- Spring MVC 解读——View,ViewResolver(转)
上一篇文章(1)(2)分析了Spring是如何调用和执行控制器方法,以及处理返回结果的,现在我们就分析下Spring如何解析返回的结果生成响应的视图. 一.概念理解 View ---View接口表示一 ...
- Spring MVC 起步
跟踪Spring MVC的请求 在请求离开浏览器时①,会带有用户所请求内容的信息,至少会包含请求的URL. 请求旅程的第一站是Spring的DispatcherServlet.与大多数基于Java的W ...
随机推荐
- 【计算机网络基础】用 telnet 检查 VPS 的某个端口是否处于监听状态
命令 telnet x.x.x.x p 其中 x.x.x.x 代表 VPS 的 IP 地址,p 代表要检查的端口号. 起因是我的 ss 不好使了.IP 没被封,查了一下,可能是 ssserver 的端 ...
- [poj] 1389 Area of Simple Polygons
原题 线段树+扫描线 对于这样一个不规则图形,我们要求他的面积有两种方法,割和补. 补显然不行,因为补完你需要求补上去的内部分不规则图形面积-- 那么怎么割呢? 像这样: 我们就转化成了无数个矩形的和 ...
- HDU 4910 HDOJ Problem about GCD BestCoder #3 第四题
首先 m = 1 时 ans = 0对于 m > 1 的 情况 由于 1 到 m-1 中所有和m互质的数字,在 对m的乘法取模 运算上形成了群 ai = ( 1<=a<m & ...
- 洛谷 P2485 [SDOI2011]计算器 解题报告
P2485 [SDOI2011]计算器 题目描述 你被要求设计一个计算器完成以下三项任务: 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最 ...
- GDB调试——经验总结
GDB调试的一些很有用经验: 1. gdb调试,如果有参数,可以在run命令后加,也可以使用set args :如果是使用gdbserver+gdb的远程调试方式,参数可以在gdbserver后面加. ...
- 扩展欧几里得(ex_gcd),中国剩余定理(CRT)讲解 有代码
扩展欧几里得算法 求逆元就不说了. ax+by=c 这个怎么求,很好推. 设d=gcd(a,b) 满足d|c方程有解,否则无解. 扩展欧几里得求出来的解是 x是 ax+by=gcd(a,b)的解. 对 ...
- Spacewalk server Installation on RHEL6
[root@yum01 ~]# rpm -Uvh http://yum.spacewalkproject.org/2.1/RHEL/6/x86_64/spacewalk-repo-2.1-2.el6. ...
- win7用户账户自动登录方法
为了计算机安全,相信使用Windows7系统的朋友大多都为自己的用户账户设置了或简单或复杂的密码,其实对于个人电脑来说,开机登录输入密码有时候会显得累赘,毕竟用户账户密码不仅仅是为了防止他人登录. 那 ...
- hdu 5072 计数+容斥原理
/* 题意: 给出n个数(n<100000), 每个数都不大于100000,数字不会有重复.现在随意抽出3个,问三个彼此互质 或者 三个彼此不互质的数目有多少. 思路: 这道题反着想,就是三个数 ...
- noip 瑞士轮 ————归并排序解法
背景 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高.后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长 ...