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
orgspringframeworkspring-webmvc4.3.8.RELEASEspring-webmvc-4.3.8.RELEASE.jar!META-INFspring.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方法实现。
- OpenDaylight与Mininet应用实战之OpenFlow1.0协议分析二
- Javascript: 世纪机器语言?
- OpenDaylight与Mininet应用实战之基本环境搭建一
- 永恒不变的魅力
- MobileNet教程(2):用TensorFlow搭建安卓手机上的图像分类App
- OpenDaylight与Mininet应用实战之流表操作三
- 天啊,这个围笑代表什么?麻省理工的AI比你更懂 | 论文+Demo
- elixir:灵丹妙药?or 徒有其名?
- OpenDaylight与Mininet应用实战之三层转发机制四
- 程序员效率指南
- 【每日播报】OpenDaylight与Mininet应用实战之复杂网络验证(五)
- Docker hackathon, teamspark 及团队协作软件设计上的思考
- 应用开发中的网络安全
- 力作|phpcms_v9.6.1 任意文件下载漏洞
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- CentOS安装Python2.7与Python2.6并存的方法
- 详解Centos下YUM安装PHP的两种方式
- linux下make命令实现输出高亮的方法
- Ubuntu彻底卸载MySQL、Apache2和Php的方法教程
- linux下如何创建守护进程的步骤
- ubuntu系统中/etc/rc.local和/etc/init.d/rc.local的区别详解
- centos6.8下hadoop3.1.1完全分布式安装指南(推荐)
- 批处理模式下运行 top 命令的方法
- 关于CentOs系统自带python和yum卸载后的解决办法
- Linux sftp命令用法总结
- CentOS 7中搭建NFS文件共享存储服务的完整步骤
- centos 7中添加一个新用户并授权的步骤详解
- Linux下Apache HTTP Server 2.4.26安装教程
- 详解linux下查看系统版本号信息的方法(总结)
- 详解Centos8 配置静态IP的实现