Spring MVC介紹(三)之 Annotation解析以及完整的執行流程
工作中對於Spring MVC我們最常用的還是使用註解的方式,那麼對於註解Spring MVC的如何處理的?
<context:component-scan base-package="com.demo.spring.mvc.control" />
<mvc:annotation-driven/>
一、annotation-driven
在前面的介紹中,我們知道了HandlerMapping以及HandlerAdapter,那麼annotation的是什麼?
對於註解:
<mvc:annotation-driven/>
它對應的handlerMapping則是:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
對應的HandlerAdapter則是:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
對應的Handler則是:
org.springframework.web.method.HandlerMethod
這些沒有配置在配置文件中,註解是怎麼實現的?
來看下NamespaceHandler接口:
org.springframework.beans.factory.xml.NamespaceHandler
package org.springframework.beans.factory.xml;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
public interface NamespaceHandler {
void init();
BeanDefinition parse(Element element, ParserContext parserContext);
BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder definition, ParserContext parserContext);
}
實現這個接口,則就可以動態的往ioc容器添加BeanDefinition,則就動態的添加了bean。
那麼這個是在哪實現的呢?
來看下spring-webmvc包裏面的spring.handlers
org\springframework\spring-webmvc\4.3.8.RELEASE\spring-webmvc-4.3.8.RELEASE.jar!\META-INF\spring.handlers
裏面內容:
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
點進去看一下 MvcNamespaceHandler 這個類:
package org.springframework.web.servlet.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
public MvcNamespaceHandler() {
}
public void init() {
this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
this.registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
this.registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
this.registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
this.registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
this.registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
this.registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
this.registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
此時我們看到了MvcNamespaceHandler extends NamespaceHandlerSupport:
public class MvcNamespaceHandler extends NamespaceHandlerSupport{...}
NamespaceHandlerSupport implements NamespaceHandler
public abstract class NamespaceHandlerSupport implements NamespaceHandler {}
NamespaceHandler接口就是我們剛剛看到的那個動態註冊BeanDefinition的接口。
並且在MvcNamespaceHandler.init() 方法中,可以看到:
this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
並且 AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {}
其中 BeanDefinitionParser 接口:
public interface BeanDefinitionParser {
BeanDefinition parse(Element element, ParserContext parserContext);
}
在 AnnotationDrivenBeanDefinitionParser.parse() 的實現方法中,可以看到
RequestMappingHandlerMapping 被註冊到ioc容器中:
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
同樣的還有RequestMappingHandlerAdapter:
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
所以這就是爲什麼添加了 mvc:annotation-driven/ 配置,就能實現mvc的整個配置了。
二、MVC完整的執行流程
之前我們介紹了MVC的異常處理和攔截器,那麼加上這兩部分,MVC的執行流程如下:
DispatcherServlet ==> 找到下面這些組件(1:n)
HandlerMapping ==> 基於url找到對應的handler (其實是找到HandlerExecutionChain)
HandlerAdapter ==> 基於handler找到對應的適配器 調用handler返回ModelAndView
(如果出現了異常)
HandlerExceptionResovler ==> 處理異常 返回errorModelAndView
(如果加入了攔截器)
HandlerInterceptor ==> 處理攔截器
ViewResolver ==> 視圖倉庫 ==> 基於viewName找到View => 解析生成Html
其中 DispatcherServlet 中調用 initStrategies 來初始化上述組件。
org.springframework.web.servlet.DispatcherServlet#initStrategies
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
有興趣可以看下這些init方法實現。