带着疑问开始

web.xml的顺序问题

先拿一个最简单的spring mvc web.xml来说问题,如下图:如果我将三者的顺序倒置或是乱置,会产生什么结果呢?

启动报错?还是加载未知结果?还是毫无影响?

结果是什么呢?让我们用实践来证明一下:go->jetty-spring-context project 现场演示

//todo 之后贴出结果

applicationContext.xml和spring-mvc-servlet.xml怎么配置

最简单的配置(这样不仅产生两个容器而且每个容器都生成一样的bean)

applicationContext:

spring-mvc-servlet.xml

正确的配置其中之一

 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!--正确的配置-->
<context:component-scan base-package="com.meituan.jetty.spring">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans> spring-mvc-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--正确的配置-->
<context:component-scan base-package="com.meituan.jetty.spring.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>

可以么?go->jetty-spring-context project 现场演示问题来了,通过结果我们发现,确实有两个容器,那么由于两个容器同时可以有一样的beans,那是否可以直接去掉ApplicationContext容器呢?

applicationContext.xml和spring-mvc-servlet.xml的初始化顺序如何

结果:applicationContext.xml的初始化优先于spring-mvc-servlet.xml

两个context容器到底是怎样的

  1. 两个容器分别是怎么初始化的呢?
  2. 为什么applicationContext容器就是mvc context容器的父容器呢?
  3. 这两个容器分别是什么类型的applicationContext实现呢?(我们知道applicationContext是接口)

下边的图是applicationContext接口的少部分实现

深入源码解决疑难

为什么不管怎么配置app.xml总是在mvc之前初始化

下边让我们用源码一步一步来分析其中的奥妙

启动jetty容器入口

......................前边还有一大段代码

初始化调用的是mms server的start方法,其实server没有start方法,是它的父类AbstractLifeCyle的start方法,然后再回调,我们来看下server的结构

在继续讲server是怎么一步步调用之前,我们需要知道两个事情

  1. ContextLoaderListener

  2. DispatcherServlet

ContextLoaderListener和DispatcherServlet的实质(插播)

contextLoaderListerner实质是实现了EventListener的一个事件监听器

相关事件通知,在我的另外一篇wiki中有详细介绍:

事件通知机制深入源码#事件通知机制深入源码-ApplicationListener

或者 直接看这里:Spring事件通知机制详解

contextLoaderListerner 的方法  contextInitialized  会被回调;
DispatcherServlet实质上是一个servlet,当然,这个不用说也看的很清楚

DispatcherServlet 的父类FrameworkServlet的方法initServletBean会被回调

   这时候我们还要知道一个事情:contextLoaderListerner 和 DispatcherServlet 是在spring的两个package里边,前者在spring-web里边,后者在spring-webmvc里边,这个对后边的理解有帮助

启动jetty容器入口(续)

为什么listener能够无论以哪种姿态都会优先于servlet执行呢?

要解决这个问题,我们先看下listener是在何时被回调的:

首先大概浏览下这个图,这里对WebAppContext和ContextHandler大概有一个映像(当然,这个是jetty的源码)

jetty启动,会初始化一个WebAppContext(WebAppContext 继承了 ServletContextHandler ,ServletContextHandler  继承了ContextHandler ,而且他们都实现了 )对象;

最终,WebAppContext对象的startContext()方法会被实现,如下图调用链:

而startContext方法又做了什么事情呢?带着疑问,我们走进下边的代码:

我们发现,ContextHandler里边存了一个listener的集合,而恰巧我们的 ContextLoaderListener 实例也在这个集合当中;

我们看到这里把ContextLoaderListener和event事件传递给了callContextInitialized方法,所以ContextLoaderListener的contextInitialized方法最终会被调用,

到此为止,我们就解释了ContextLoaderListener是会被合理的初始化的;

至于ContextLoaderListener初始化的详细过程,请看这里:浅谈jetty如何初始化spring容器-ContextLoaderListener初始化context容器的过程

咦?好像有什么不对的地方。哦,对,本来是WebAppContext的startContext方法,怎么会跑到ContextHandler的startContext方法,看上图,

是子类父类的关系,原来如此;

看调用链,再来说说 boot 本来调用server的start,为什么会走到lifeCycle呢?

原来 server 继承了 AbstractLifeCycle,jetty源代码里边大量运用了 模板方法和类模板方法,我们开发的时候也可以学习这种设计模式,减少重复代码,提高代码复用率。

讲了这么多,还没讲到 为什么 listener 总是在 servlet之前执行呢?

莫急,且听下边讲解

如下,WebAppContext的 doStart 方法被调用,此时WebAppContext自己实现了一部分,其余直接调用父类->ContextHandler的doStart方法

(咦,不对,父类不是ServletContextHandler么;哦,ServletContextHandler并未重写这个方法)

接下来调用ContextHandler的doStart方法

ContextHandler再次调用子类WebAppContext的方法 startContext()

WebAppContext 首先调用 startWebApp,然后 startWebApp 再次调用父类 ServletContextHandler的 startContext方法

这里就比较有意思了:ServletContextHandler首先调用父类,也就是ContextHandler的startContext方法,还记得父类的这个方法发生了什么吗?

对!父类这个方法里边初始化了 ContextLoadListener ,也就是初始化了所有的 事件通知 !!!

事件通知完成之后,开始调用servlet的initialize方法,初始化servlet;servlet初始化详解:深入浅出jetty初始化spring容器-DispatcherServlet初始化context容器的过程

  也就是说:frameworkServlet初始化方法的回调是由ServletContextHandler的startContext方法引起的!!!

看下边 listener和servlet的执行顺序:

至此为止,我们剖析了 jetty初始化 为什么 listener的执行一定会先于servlet!!!

ContextLoaderListener初始化context容器的过程

ContextLoaderListener结构

ContextLoaderListener入口

首先,回调ContextLoaderListener的contextInitialized方法

然后调用父类ContextLoader的contextInitialized方法,第一次初始化的时候 org.springframework.web.context.WebApplicationContext.ROOT == null

紧接着在1的时候创建context

我们看看 context 到底是怎么创建的?创建的是哪种类型?红框决定了创建哪种类型的 applicationContext

如下图,通过strategy决定创建哪种类型

strategy又是怎么初始化的呢?

look

可见,是这个配置文件决定了,wepApplicationContext的类型是XmlWebApplicationContext,接下来是configAndRefresh

最终调用 AbstractApplicationContext的refresh方法,根据配置文件内容,开始初始化;

AbstractApplicationContext的refresh的初始化都知道吧?不知道的话,可以看我这篇关于spring初始化顺序的文章:Spring Init&Destroy#spring容器的主要入口

DispatcherServlet初始化context容器的过程

DispatcherServlet结构

DispatcherServlet入口

初始化webApplicationContext,

创建webApplicationContext

这里的contextClass是这么决定的

最终也是调用refresh实例化的

最终完成第二个容器的初始化

jetty加载spring-context容器源码分析的更多相关文章

  1. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

  2. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  3. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

  4. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  5. Spring IOC 容器源码分析 - 循环依赖的解决办法

    1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...

  6. Spring IOC 容器源码分析 - 创建原始 bean 对象

    1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...

  7. Spring IOC 容器源码分析 - 创建单例 bean 的过程

    1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...

  8. 最简 Spring IOC 容器源码分析

    前言 BeanDefinition BeanFactory 简介 Web 容器启动过程 bean 的加载 FactoryBean 循环依赖 bean 生命周期 公众号 前言 许多文章都是分析的 xml ...

  9. Spring Boot JDBC:加载DataSource过程的源码分析及yml中DataSource的配置

    装载至:https://www.cnblogs.com/storml/p/8611388.html Spring Boot实现了自动加载DataSource及相关配置.当然,使用时加上@EnableA ...

  10. Spring IOC 容器源码分析

    声明!非原创,本文出处 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 S ...

随机推荐

  1. Hbase0.98.4/Hadoop2.4.1整合小结【原创】

    设定hbase的数据目录,修改conf/hbase-site.xml <configuration> <property> <name>hbase.cluster. ...

  2. Spark源码系列(六)Shuffle的过程解析

    Spark大会上,所有的演讲嘉宾都认为shuffle是最影响性能的地方,但是又无可奈何.之前去百度面试hadoop的时候,也被问到了这个问题,直接回答了不知道. 这篇文章主要是沿着下面几个问题来开展: ...

  3. truncate/drop表非常慢,怎么办?用硬链接,极速体验

    这个这个,我必须花巨大篇幅,记录下今天清空表记录的英雄壮举,可知道一个drop操作,执行了一下午啊一下午,这是要急出翔的节奏..呵呵,下面开始 我的需求:某表因历史原因,积压了1亿条记录,约占360G ...

  4. mysql 性能优化 配置优化

    http://download.csdn.net/album/detail/1397/2

  5. using-ef-code-first-with-an-existing-database

    http://weblogs.asp.net/scottgu/using-ef-code-first-with-an-existing-database http://weblogs.asp.net/ ...

  6. efwplus框架介绍

    此框架得到博客园大神@张善友的关注,建议我写一篇此框架的最新介绍,好在@dotNet跨平台公众号上推荐给大家,得到大神的指示当然激动,马不停蹄的赶出此文,供大家参考!   一.使用efwplus框架的 ...

  7. zeromq 测试总结

    总结 测试项目 github (https://github.com/solq360/jmzq) 非常不稳定 pub/sub 模式 30W压测丢了27W条消息,官方没有给出任何的发送状态供业务层处理 ...

  8. MyBatis自定义数据映射TypeHandler

    从网上看到的帖子,感觉内容非常好,拷过来的(不愿意转载,不然被作者删除了,这么好的帖子就看不到了). 原文:http://my.oschina.net/amoshuang/blog/134199 在M ...

  9. Spring3 MVC入门示例

    Spring3 MVC 介绍: 1. Spring MVC 是Spring 框架的Web组件,能够开发WEB工程 2. 能与其它框架(Struts2)很好的集成 3.  Spring MVC 是以se ...

  10. DDD:小议 BoundexContext 设计

    背景 看了这篇文章:Coding for Domain-Driven Design: Tips for Data-Focused Devs,对 BoundedContext 的设计有了一点新的体会,记 ...