带着疑问开始

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. 编译 curl with ssl

    安装 openssh后,使用 curl 的 ./configure --with-ssl 时,报错“找不到 ssl”.因为 curl在 /usr/local/ssl的安装目录下找动态连接库.而ssl默 ...

  2. Android中GridView使用总结

    1.http://blog.csdn.net/hellogv/article/details/4567095  基础篇,GridView最基本的用法 2.http://my.eoe.cn/cainia ...

  3. AIDL示例

    背景 最近在考虑项目重构的时候,考虑将项目拆分成两个APK,一个用于数据服务,一个用于UI展示. 数据服务APK向自己编写APK提供数据,同时也可以向第三方提供数据.考虑使用这样的方式代替向第三方提供 ...

  4. iOS 基础复习

    silverlight知识点:linqToSQL.视图.存储过程.索引.触发器 数据结构:数组.栈.队列.链表.属.图. 排序算法:插入.选择.交换(冒泡).归并 网络开发:HTTP短连接.socke ...

  5. WPF中如何用代码触发按钮Click处理

    btnOk.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

  6. SQLite 入门教程 (终端)命令

    一.基本简介 SQLite 是一个自持的(self-contained).无服务器的.零配置的.事务型的关系型数据库引擎.因为他很小,所以也可以作为嵌入式数据库内建在你的应用程序中.SQLite 被应 ...

  7. 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型

    比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...

  8. 程序员编程艺术第三十六~三十七章、搜索智能提示suggestion,附近点搜索

    第三十六~三十七章.搜索智能提示suggestion,附近地点搜索 作者:July.致谢:caopengcs.胡果果.时间:二零一三年九月七日. 题记 写博的近三年,整理了太多太多的笔试面试题,如微软 ...

  9. Failure is not fatal, but failure to change might be.

    Failure is not fatal, but failure to change might be. 失败不是致命的,但无法改变却可能是致命的.

  10. 资源 | 数十种TensorFlow实现案例汇集:代码+笔记

    选自 Github 机器之心编译 参与:吴攀.李亚洲 这是使用 TensorFlow 实现流行的机器学习算法的教程汇集.本汇集的目标是让读者可以轻松通过案例深入 TensorFlow. 这些案例适合那 ...