一、前沿

在 Spring MVC 的项目中,我们经常使用 <mvc:annotation-driven> 这个配置,那么这个配置到底是做什么的呢?下面来分析一下,首先找到 mvc 的命名空间的定义,如下图:

从上述图中可知,annotation-driven 配置的实现类应该是定义在了 MvcNamespaceHandler 类中,是不是这样的呢?下面我们看下 MvcNamespaceHandler 源码

二、MvcNamespaceHandler

MvcNamespaceHandler 源码如下:

/*** {@link NamespaceHandler} for Spring MVC configuration namespace.** @author Keith Donald* @author Jeremy Grelle* @author Sebastien Deleuze* @since 3.0*/
public class MvcNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {// 注册 annotation-driven 标签的解析器 AnnotationDrivenBeanDefinitionParser,用来解析 ControllerregisterBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());// 注册 default-servlet-handler 标签的解析器 DefaultServletHandlerBeanDefinitionParser,用来解析静态资源文件(html、jsp、js和css等)registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());// 注册 interceptors 标签的解析器 InterceptorsBeanDefinitionParser,用来解析拦截器registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());// 注册 resources 标签的解析器 ResourcesBeanDefinitionParser,用来解析资源文件registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());// 注册 view-controller、redirect-view-controller、status-controller 标签的解析器 ViewControllerBeanDefinitionParser,用来解析视图viewregisterBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());// 注册 view-resolvers 标签的解析器 ViewResolversBeanDefinitionParser,用来解析视图解析器registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());// 注册 freemarker-configurer 标签的解析器 FreeMarkerConfigurerBeanDefinitionParser,用来解析 freemarker 配置registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());// 注册 groovy-configurer 标签的解析器 GroovyMarkupConfigurerBeanDefinitionParser,用来解析 groovy 配置registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());// 注册 script-template-configurer 标签的解析器 ScriptTemplateConfigurerBeanDefinitionParser,用来解析 script 脚本模板配置registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());// 注册 cors 标签的解析器 CorsBeanDefinitionParser,用来解析跨域registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());}}

从上述源码中可知 annotation-driven 配置对应的解析类 AnnotationDrivenBeanDefinitionParser 确实是定义在 MvcNamespaceHandler 的 init 方法中,那么 annotation-driven 配置实现的具体业务肯定在 AnnotationDrivenBeanDefinitionParser 类中,下面我们分析一下 AnnotationDrivenBeanDefinitionParser 源码

三、AnnotationDrivenBeanDefinitionParser

AnnotationDrivenBeanDefinitionParser 的 parse 方法实现了具体的解析逻辑,源码如下:

/*** A {@link BeanDefinitionParser} that provides the configuration for the* {@code <annotation-driven/>} MVC namespace element.** <p>This class registers the following {@link HandlerMapping HandlerMappings}:</p>* <ul>* <li>{@link RequestMappingHandlerMapping}* 将请求映射到带注解的控制器方法时,按照0排序,例如 @RequestMapping("/test")* ordered at 0 for mapping requests to annotated controller methods.* <li>{@link BeanNameUrlHandlerMapping}* 将URL路径映射到控制器bean名称时,按照2排序* ordered at 2 to map URL paths to controller bean names.* </ul>** <p><strong>Note:</strong> Additional HandlerMappings may be registered* as a result of using the {@code <view-controller>} or the* {@code <resources>} MVC namespace elements.** <p>This class registers the following {@link HandlerAdapter HandlerAdapters}:* <ul>* <li>{@link RequestMappingHandlerAdapter}* 处理带有@controller注解的适配器(支持自定义的参数和返回值),对应于 RequestMappingHandlerMapping,例如 @RequestMapping("/test")* for processing requests with annotated controller methods.* <li>{@link HttpRequestHandlerAdapter}* 处理带有 HttpRequestHandlers 的适配器* for processing requests with {@link HttpRequestHandler HttpRequestHandlers}.* <li>{@link SimpleControllerHandlerAdapter}* 处理基于 Controllers 接口的适配器* for processing requests with interface-based {@link Controller Controllers}.* </ul>** 异常处理器* <p>This class registers the following {@link HandlerExceptionResolver HandlerExceptionResolvers}:* <ul>* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through* {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated* with {@link org.springframework.web.bind.annotation.ResponseStatus}.* <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring* exception types* </ul>** <p>This class registers an {@link org.springframework.util.AntPathMatcher}* and a {@link org.springframework.web.util.UrlPathHelper} to be used by:* <ul>* <li>the {@link RequestMappingHandlerMapping},* <li>the {@link HandlerMapping} for ViewControllers* <li>and the {@link HandlerMapping} for serving resources* </ul>* Note that those beans can be configured by using the {@code path-matching}* MVC namespace element.** <p>Both the {@link RequestMappingHandlerAdapter} and the* {@link ExceptionHandlerExceptionResolver} are configured with instances of* the following by default:* <ul>* <li>A {@link ContentNegotiationManager}* <li>A {@link DefaultFormattingConversionService}* <li>A {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean}* if a JSR-303 implementation is available on the classpath* <li>A range of {@link HttpMessageConverter HttpMessageConverters} depending on which third-party* libraries are available on the classpath.* </ul>** @author Keith Donald* @author Juergen Hoeller* @author Arjen Poutsma* @author Rossen Stoyanchev* @author Brian Clozel* @author Agim Emruli* @since 3.0*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext context) {Object source = context.extractSource(element);XmlReaderContext readerContext = context.getReaderContext();CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);context.pushContainingComponent(compDefinition);RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, context);// 定义 RequestMappingHandlerMappingRootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);handlerMappingDef.setSource(source);handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 排序值为 0handlerMappingDef.getPropertyValues().add("order", 0);handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);if (element.hasAttribute("enable-matrix-variables")) {Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);}configurePathMatchingProperties(handlerMappingDef, element, context);// 注册 RequestMappingHandlerMapping 类型对应的 RootBeanDefinitionreaderContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);RuntimeBeanReference conversionService = getConversionService(element, source, context);RuntimeBeanReference validator = getValidator(element, source, context);RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);bindingDef.setSource(source);bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);bindingDef.getPropertyValues().add("conversionService", conversionService);bindingDef.getPropertyValues().add("validator", validator);bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);ManagedList<?> messageConverters = getMessageConverters(element, source, context);ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);String asyncTimeout = getAsyncTimeout(element);RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, context);ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, context);// 定义 RequestMappingHandlerAdapterRootBeanDefinition 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);addRequestBodyAdvice(handlerAdapterDef);addResponseBodyAdvice(handlerAdapterDef);if (element.hasAttribute("ignore-default-model-on-redirect")) {Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));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);// 注册 RequestMappingHandlerAdapter 对应的 RootBeanDefinitionreaderContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);RootBeanDefinition uriContributorDef =new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);uriContributorDef.setSource(source);uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);csInterceptorDef.setSource(source);csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);mappedInterceptorDef.setSource(source);mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);// 定义 ExceptionHandlerExceptionResolver 异常处理器RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);methodExceptionResolver.setSource(source);methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);// 排序值为 0methodExceptionResolver.getPropertyValues().add("order", 0);addResponseBodyAdvice(methodExceptionResolver);if (argumentResolvers != null) {methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);}if (returnValueHandlers != null) {methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);}String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);// 定义 ResponseStatusExceptionResolver 返回状态异常解析器RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);statusExceptionResolver.setSource(source);statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 排序值为 1statusExceptionResolver.getPropertyValues().add("order", 1);String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);// 定义Spring中已知的异常解析器RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);defaultExceptionResolver.setSource(source);defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 排序值为 2defaultExceptionResolver.getPropertyValues().add("order", 2);String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);// 将上面所有的 bean 组件注册到上下文中context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"// 注册默认的一些组件,例如 BeanNameUrlHandlerMapping、HttpRequestHandlerAdapter、// SimpleControllerHandlerAdapter 和 HandlerMappingIntrospectorMvcNamespaceUtils.registerDefaultComponents(context, source);context.popAndRegisterContainingComponent();return null;}
}

从上述源码中可以看出,在 AnnotationDrivenBeanDefinitionParser 中主要实现了注册了很多 bean 的功能,其中我们最关心的就是 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 两个类,功能分别如图:

RequestMappingHandlerMappingHandlerMapping 的实现类,它处理的是 @RequestMapping 注解,并将其注册到映射表中,即 url 对应的 Controller 的 方法

RequestMappingHandlerAdapterHandlerAdapter 的实现类,它是处理请求的适配器,就是确定调用哪个 Controller 的 哪个方法

到这里,AnnotationDrivenBeanDefinitionParser 的源码就分析完了,其中没有什么太多复杂的逻辑,代码注释都写清楚了

四、annotation-driven 作用

通过阅读 AnnotationDrivenBeanDefinitionParser 的源码可知,annotation-driven 配置的作用如下:

1)、主要是注册了 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter bean,存储了请求url到Controller方法的映射关系

2)、注册了异常处理器

五、总结

Spring MVC 中如果配置了 <mvc:annotation-driven> ,则所有的 Controller 就会被解析,所以相应的 .do 请求就会被 Controller 处理,因此这个配置至关重要。当请求没有匹配到处理类(其中包括没有配置 <mvc:annotation-driven> 或者 访问的是静态资源文件)时,就会去找  <mvc:default-servlet-handler> (处理静态资源文件)配置的 DefaultServletHttpRequestHandler 默认处理器处理了

annotation-driven 配置详解相关推荐

  1. 【笔记】spring的注解回顾,springboot-restful项目结构介绍 springboot-freemarker ⼯程配置详解

    注解 学Spring boot有一阵子了,总结一下它的注解. @Controller :修饰class,⽤来创建处理http请求的对象 @RestController :Spring4之后加⼊的注解, ...

  2. mybatis获取表名_mybatis plus 的动态表名的配置详解

    mybatis plus简介 详见mybatis plus的官网 业务要求 业务上要求存储数据的时候根据某个字段动态的选择数据要存储的表. 如根据code字段: code->[1001,1002 ...

  3. java 配置jmstemplate_SpringBoot集成JmsTemplate(队列模式和主题模式)及xml和JavaConfig配置详解...

    1.导入jar包: org.springframework.boot spring-boot-starter-activemq org.apache.activemq activemq-pool 2. ...

  4. SpringBoot配置详解

    SpringBoot配置详解 本文链接:http://blog.battcn.com/2018/04/22/springboot/v2-config-properties/ 上一篇介绍了SpringB ...

  5. easycode 表配置_idea的easyCode的 MybatisPlus模板的配置详解

    EasyCode 插件 EasyCode 插件 是一款根据表结构生成代码的很方便的Idea插件, 强烈推荐. 并且可以自定义模板来控制生成的类 我在使用的过程中发现一些问题,现在把解决办法记录下来, ...

  6. SpringMVC 框架系列之组件概述与配置详解

    在上一篇文章 SpringMVC 框架系列之初识与入门实例 的实例中,我们已经知道,SpringMVC 框架是一个 web 层的框架,本篇文章就详细解释一下 SpringMVC 框架具体文件的配置以及 ...

  7. ssh2的application.xml配置文件配置详解

    ssh2的application.xml配置文件配置详解 1.导入其他的配置文件.在ssh项目中可以导入其他的配置文件,导入的格式为: <import resource="classp ...

  8. JavaWeb web.xml配置详解

    参考: XML 教程 Java web之web.xml配置详解 Javaweb三大组件是:Servlet,Filter,Listener. 1.Servlet Servlet作为中转处理的容器,连接了 ...

  9. Spring使用指南 ~ 4、ApplicationContext 配置详解

    ApplicationContext 配置详解 一.应用程序事件 package com.luo.spring.guides.event.xml;import org.springframework. ...

  10. SpringMVC基础--spring MVC配置详解

    牧涛 --<-<-<@态度决定一切→_→... 博客园 首页 新闻 新随笔 联系 管理 订阅 随笔- 171  文章- 3  评论- 79  spring MVC配置详解 现在主流的 ...

最新文章

  1. 第十五届全国大学生智能汽车竞赛 人工智能创意组总决赛
  2. 行路的心情-让自己慢下来(11)
  3. Zookeeper应用场景理解
  4. WF 创建 SQL 持久性数据库
  5. AXI_01 《AXI总线系列文章》由来
  6. 为什么机器学习算法要与人类水平比较
  7. 宝塔linux_Linux虚拟机上快速搭建宝塔 部署PHP运行环境
  8. Ubuntu下搜狗输入法突然无法输入中文
  9. 多窗口售票:单件模式多线程实现
  10. leetcode185 Department Top Three Salaries
  11. cake 简单思维题
  12. oracle select between and,oracle中的between和and的问题 | 学步园
  13. 关于数模中编程的一点愚见
  14. 苹果电脑 / Mac 开机密码忘记了应该如何操作?
  15. asp.net 中 使用ajax 和浏览器的关系
  16. echarts饼图, 中间显示总数
  17. 蝴蝶曲线python_蝴组词有哪些?除了蝴蝶还可以组什么?蝴字的基本字义
  18. 线性规划python
  19. 《把时间当做朋友-李笑来》
  20. Internet浏览器64位Java插件使用方法

热门文章

  1. NeurIPS2020 Generalized Focal Loss论文翻译
  2. 以下数据库收录外文文献全文的有_【讲座】外文文献的检索与获取
  3. 《偷影子的人》书评分享:那份属于我的感动
  4. python实现列表元素互异
  5. CSS 框架 Bulma 教程
  6. opengl纹理过滤
  7. android开发 app消息提醒功能,APP消息提醒设计:ios和android的最佳设计方案 – 25学堂...
  8. 瞬变抑制二极管(TVS),如何选型?
  9. 移动端安卓vin码/车架号识别
  10. 金蝶KIS专业版V14.1即时库存查询表添加字段条形码|商品描述|最低最高存量