天天看点

【spring mvc】annotation-driven 配置详解1. 前言2. MvcNamespaceHandler3、AnnotationDrivenBeanDefinitionParser4、总结

文章目录

  • 1. 前言
  • 2. MvcNamespaceHandler
  • 3、AnnotationDrivenBeanDefinitionParser
  • 4、总结

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 的命名空间的定义,如下图:

【spring mvc】annotation-driven 配置详解1. 前言2. MvcNamespaceHandler3、AnnotationDrivenBeanDefinitionParser4、总结
【spring mvc】annotation-driven 配置详解1. 前言2. MvcNamespaceHandler3、AnnotationDrivenBeanDefinitionParser4、总结

从上述图中可知,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 默认处理器处理了