文章目錄
- 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 的命名空間的定義,如下圖:
從上述圖中可知,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 預設處理器處理了