天天看點

Spring MVC介紹(三)之 Annotation解析以及完整的執行流程

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方法實作。