在阅读本文前,最好先阅读以下内容(当然,如果对 Servlet 已经有所了解,则可跳过):

http://www.cnblogs.com/cyhbyw/p/8682078.html

http://www.cnblogs.com/cyhbyw/p/8682307.html

http://www.cnblogs.com/cyhbyw/p/8682632.html

============分隔线==========================

在使用 SpringMVC 进行 Web 开发时,通常在 web.xml 中配置的 Servlet  都是 org.springframework.web.servlet.DispatcherServlet,那这个 DispatcherServlet 又是如何被 Tomcat 容器(或者其它容器)启动并加载进来的呢?

带着这个问题,写了个简单Demo进行源码调试。

Demo代码地址:https://github.com/cyhbyw/springMVC_atguigu_TongGang

Demo代码工程:springMVC_DebugSourceCode

首先从静态代码的角度,可以看到 DispatcherServlet 类的承继结构如下图所示

  • HttpServlet 及以上部分是 Servlet 标准中提供的接口及类
  • DispatcherServlet、FrameworkServlet、HttpServletBean 三者是 SpringMVC 提供的类,且后者依次分别是前者的父类

现在开始源码调试:

首先调用了 DispatcherServlet 的构造函数,并且从堆栈信息中可以看出,这是由 Tomcat 调用的

接下来当然是调用父类 FrameworkServlet 的构造函数

构造函数完成后,调用 Servlet 生命周期的 init() 方法;

提示,此处是 HttpServletBean 中的 init() 方法重载了GenericServlet中的 init() 方法;

这就是之前说的,建议重载这个空的 init() 方法而不建议重载那个 init(ServletConfig config) 方法,看来 SpringMVC 也确实是这样做的;

接下来代码走到 Line136行,初始化容器Bean

接下来代码走到 Line493 行,初始化Web应用上下文

接下来代码走到 Line552 行,创建Web应用上下文

获取到需要创建的Bean的Class

直接调用 getContextClass() 方法

而它内置的 contextClass 其实就是 XmlWebApplicationContext

XmlWebApplicationContext 的继承结构如下图所示,不用说,肯定也是 ApplicationContext 家庭中的成员

Line627 行就实例化了 XmlWebApplicationContext

同时,代码会走到 Line633 行,配置并刷新Web应用上下文

Line655 添加了一个应用监听器;(重要,后面会取出来用到)

注意,这里方法入参处的 ApplicationListener degegate = FrameworkServlet$ContextRefreshListener,且成员变量中的 GenericApplicationListener degegate = GenericApplicationListenerAdapter;同时方法入参中的 degegate 会被 GenericApplicationListenerAdapter 包装后赋值给成员变量的 delegate(有点绕,所以用了三种颜色以示区分)

可以这样来记忆或理解:

一、对于 SourceFilteringListener 来说,其成员变量 degegate 的类型是 GenericApplicationListenerAdapter

二、对于 GenericApplicationListenerAdapter  来说,它也有个叫做 delegate 的成员变量,且这个 delegate 的类型是 FrameworkServlet$ContextRefreshListener

(虽然这两个同名叫做 delegate 的成员变量有点绕,但它们比较重要,后面会用到)

SourceFilteringListener 构造完成后,回到上一层方法调用处;

接下来,代码走到 Line667 行进行刷新

这个 refresh() 方法是 Spring 中非常重要的一个方法,会调用多个方法执行多个动作,包括初始化BeanFactory、容器后处理器处理、初始化MessageSource、注册监听器等动作;

refresh() 方法非常重要!!!

refresh() 方法非常重要!!!

refresh() 方法非常重要!!!

这里,暂时关心的是,它会读取我们为 SpringMVC 所编写的配置文件中的内容(如 annotation-driven & default-servlet-handler 等,这属于上一篇文章的内容,具体可参见 这里);

之后,它会调用 Line541 行的方法,完成刷新

经过几个方法的调用,代码走到 Line136 ,并且此处的 listener=SourceFilteringListener(通过 Line125 获取到之前添加进来的Listener,且这个 listener=SourceFilteringListener)

然后调用 SourceFilteringListener 的 onApplicationEvent() 方法

继续调用

继续调用,注意当前类是 SourceFilteringListener,且这个 delegate=GenericApplicationListenerAdapter(就是之前设置进来的)

现在来到 GenericApplicationListenerAdapter 类中,注意此处的 delegate=FrameworkServlet$ContextRefreshListener(之前设置进来的),所以,实际上会调到 ContextRefreshListener 的 onApplicationEvent() 方法

调用到 FrameworkServlet 中内部类 ContextRefreshListener  的 onApplicationEvent() 方法,而它又是直接调用到 FrameworkServlet  的 onApplicationEvent() 方法

这个方法会调用到 onRefresh() 方法;而 FrameworkServlet 的 onRefresh() 方法默认实现为空(让子类扩展)

自然,会调用到 DispatcherServlet 的 onRefresh() 方法上,而这个方法实际上调用了其它的一系列初始化方法,如 initHandlerMappings(context) & initHandlerAdapters(context),这样在容器启动的过程中,就已经初始化完成 HandlerMapping & HandlerAdapter

至此,DispatcherServlet 中与 Servlet 生命周期相关的调用构造器及 init() 方法就已经基本完成了,接下来,就是对请求的响应啦,这会依次调用 Servlet 的 service() 方法,不属于本文范畴啦~~~

简单总结起来,Tomcat 容器启动并加载 DispatcherServlet 时所做的主要工作如下:

  • 调用 DispatcherServlet 的构造器(当然也会调用父类的构造器,不过构造器默认实现为空;这个动作很短,基本上可以忽略)
  • 调用 GenericServlet 的 init() 方法,不过,这被 HttpServletBean 重载了;同时,重载的 HttpServletBean  的 init() 方法调用了 initServletBean() 方法;而 initServletBean() 方法会完成以下操作:
  1. 初始化(创建)一个 WebApplicationContext(实际上是 WebApplicationContext 类)
  2. 调用 AbstractApplicationContext 的 refresh() 方法,完成 BeanFactory创建、读取 SpringMVC 配置文件内容、处理容器后处理器、初始化MessageResource、注册监听器等工作
  3. 通过上一步中读取到的内容,初始化 HandlerMapping & HandlerAdapter 等工作
  4. ==上面3个步骤才是重要内容==

总的来说,DispatcherServlet 还是一个 Servlet,遵循 constructor() --> init() --> service() --> destroy() 方法的调用流程。只不过,它的这个 init() 方法确实比较复杂(本文内容)。

SpringMVC DispatcherServlet 启动和加载过程(源码调试)的更多相关文章

  1. spring启动component-scan类扫描加载过程---源码分析

    http://blog.csdn.net/xieyuooo/article/details/9089441#comments

  2. jboss之启动加载过程详解

    今天看了看jboss的boot.log和server.log日志,结合自己的理解和其他的资料,现对jboss的启动和加载过程做出如下总结: boot.xml是服务器的启动过程的日志,不涉及后续的操作过 ...

  3. Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析

    Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...

  4. ElasticSearch 启动时加载 Analyzer 源码分析

    ElasticSearch 启动时加载 Analyzer 源码分析 本文介绍 ElasticSearch启动时如何创建.加载Analyzer,主要的参考资料是Lucene中关于Analyzer官方文档 ...

  5. 微服务架构 | *2.3 Spring Cloud 启动及加载配置文件源码分析(以 Nacos 为例)

    目录 前言 1. Spring Cloud 什么时候加载配置文件 2. 准备 Environment 配置环境 2.1 配置 Environment 环境 SpringApplication.prep ...

  6. SpringMVC跨域问题排查以及源码实现

    SpringMVC跨域问题排查以及源码实现 最近一次项目中,将SpringMVC版本从4.1.1升级到4.3.10,出现跨域失败的情况.关于同源策略和跨域解决方案,网上有很多资料. 项目采用的方式是通 ...

  7. Springboot学习04-默认错误页面加载机制源码分析

    Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...

  8. Mybatis+SpringMVC实现分页查询(附源码)

    Maven+Mybatis+Spring+SpringMVC实现分页查询(附源码) 一.项目搭建 关于项目搭建,小宝鸽以前写过一篇Spirng+SpringMVC+Maven+Mybatis+MySQ ...

  9. Volley 图片加载相关源码解析

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47721631: 本文出自:[张鸿洋的博客] 一 概述 最近在完善图片加载方面的 ...

随机推荐

  1. 小白学爬虫-设置Selenium+Chrome代理

    微博登录限制了错误次数···加上Cookie大批账号被封需要从Cookie池中 剔除被封的账号··· 需要使用代理··· 无赖百度了大半天都是特么的啥玩意儿???结果换成了 Google手到擒来 分分 ...

  2. WPF自学入门(二)WPF-XAML布局控件

    上一篇介绍了xaml基本知识,我们已经知道了WPF简单的语法.那么接下来,我们要认识一下WPF的布局容器.布局容器可以使控件按照分类显示,我们一起来看看WPF里面可以使用哪些布局容器用来布局. 在WP ...

  3. 前端测试框架对比(js单元测试框架对比)

    前端测试框架对比(js单元测试框架对比) 本文主要目的在于横评业界主流的几款前端框架,顺带说下相关的一些内容. 测试分类 通常应用会有 单元测试(Unit tests) 和 功能测试(Function ...

  4. zk个人入门学习总结(1)

    ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题.ZooKeeper允许开发人员专注于核 ...

  5. [MyBatis]DAO层只写接口,不用写实现类

    团队开发一个项目,由老大架了一个框架,遇到了DAO层不用写接口了,我也是用了2次才记住这个事的,因为自己一直都是习惯于写DAO层的实现类,所以,习惯性的还是写了个实现类.于是遇到错误了. 找不到那个方 ...

  6. 洛谷P2617 Dynamic Ranking(主席树,树套树,树状数组)

    洛谷题目传送门 YCB巨佬对此题有详细的讲解.%YCB%请点这里 思路分析 不能套用静态主席树的方法了.因为的\(N\)个线段树相互纠缠,一旦改了一个点,整个主席树统统都要改一遍...... 话说我真 ...

  7. _vimrc 的配置

    windows set nocompatible set guifont=Consolas:h17 color molokai set backspace=2 set sts=4 set ts=4 s ...

  8. HiHocoder1419 : 后缀数组四·重复旋律4&[SPOJ]REPEATS:Repeats

    题面 Hihocoder Vjudge Sol 题目的提示说的也非常好 我对求\(LCP(P - L + len \% l, P + len \% L)\)做补充 \(len=LCP(P, P + L ...

  9. equals与==号的区别?

    equals与 == 的区别 初学Java的人(me),有很长一段时间对equals()这个方法感到很懊恼,实在是弄不明白到底何时比较的是地址,又什么时候比较内容呢?因为要找工作,要面试.本人通过查阅 ...

  10. docker 一键安装zabbix server、zabbix agent

    基本原理.须知:1.zabbix 分为zabbix server和zabbix agent,其中zabbix server需要web环境,并且其数据存储在独立的数据库中:2.docker是一种容器服务 ...