天天看點

【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 預設處理器處理了