1. 前言

我们经常使用 mvc:annotation-driven 这个配置,那么这个配置到底是做什么的呢?

主要用于spring mvc 中的annotation注解功能,作用是帮我们注入一些内置bean,例如RequestMappingHandlerMappingRequestMappingHandlerAdapter等,这些类是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 默认处理器处理了

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐