1. 前言
我们经常使用 mvc:annotation-driven 这个配置,那么这个配置到底是做什么的呢?
主要用于spring mvc 中的annotation注解功能,作用是帮我们注入一些内置bean,例如RequestMappingHandlerMapping
和 RequestMappingHandlerAdapter
等,这些类是Aware的子类,能完成特定的供能,例如:
RequestMappingHandlerMapping负责解析@RequestMapping("/helloworld")
注解。
主要是解析spring mvc的一些标签和语法!
等价于下面配置:
<!--HandlerMapping-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
</bean>
<!-- HandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- HadnlerExceptionResolvers-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver"></bean>
<bean class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"></bean>
从上面可以看到,RequestMapping会注册多个子类,spring会用chain链式尝试逐一匹配,RequestMappingHandlerMapping或BeanNameUrlHandlerMapping任意一个能匹配上收到的url,都可以正确处理。
下面来分析一下,首先找到 mvc 的命名空间的定义,如下图:
从上述图中可知,annotation-driven 配置的实现类应该是定义在了 MvcNamespaceHandler 类中,是不是这样的呢?下面我们看下 MvcNamespaceHandler 源码:
2. 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 {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
从上述源码中可知 annotation-driven 配置对应的解析类 AnnotationDrivenBeanDefinitionParser 确实是定义在 MvcNamespaceHandler 的 init 方法中,那么 annotation-driven 配置实现的具体业务肯定在 AnnotationDrivenBeanDefinitionParser 类中,下面我们分析一下 AnnotationDrivenBeanDefinitionParser 源码
3、AnnotationDrivenBeanDefinitionParser
AnnotationDrivenBeanDefinitionParser 的 parse 方法实现了具体的解析逻辑,源码如下:
public BeanDefinition parse(Element element, ParserContext parserContext) {
......
// 定义 RequestMappingHandlerMapping
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
.....
// 注册 RequestMappingHandlerMapping 类型对应的 RootBeanDefinition
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);
// 定义 RequestMappingHandlerAdapter
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
......
// 注册 RequestMappingHandlerAdapter 对应的 RootBeanDefinition
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef);
从上述源码中可以看出,在 AnnotationDrivenBeanDefinitionParser 中主要实现了注册了很多 bean 的功能,其中我们最关心的就是 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 两个类
4、总结
Spring MVC 中如果配置了 <mvc:annotation-driven>
,则所有的 Controller 就会被解析,所以相应的 .do 请求就会被 Controller 处理,因此这个配置至关重要。当请求没有匹配到处理类(其中包括没有配置 <mvc:annotation-driven>
或者 访问的是静态资源文件)时,就会去找 <mvc:default-servlet-handler>
(处理静态资源文件)配置的 DefaultServletHttpRequestHandler 默认处理器处理了