目录
具体而言,Spring中的容器类可以分为两大类。
-
一类是由BeanFactory接口定义的核心容器。BeanFactory位于整个容器类体系结构的顶端,其基本实现类为DefaultListableBeanFactory。之所以称其为核心容器,是因为该类容器实现IOC的核心功能:比如配置文件的加载解析,Bean依赖的注入以及生命周期的管理等。BeanFactory作为Spring框架的基础设施,面向Spring框架本身,一般不会被用户直接使用。
-
另一类则是由ApplicationContext接口定义的容器,通常译为应用上下文,不过称其为应用容器可能更形象些。它在BeanFactory提供的核心IOC功能之上作了扩展。通常ApplicationContext的实现类内部都持有一个BeanFactory的实例,IOC容器的核心功能会交由它去完成。而ApplicationContext本身,则专注于在应用层对BeanFactory作扩展,比如提供对国际化的支持,支持框架级的事件监听机制以及增加了很多对应用环境的适配等。ApplicationContext面向的是使用Spring框架的开发者。开发中经常使用的ClassPathXmlApplicationContext就是典型的Spring的应用容器,也是要进行解读的IOC容器。
1.3 解读IOC容器启动流程的意义
-
1.IOC模块是整个Spring框架的核心,是实现其他模块的基础。IOC容器在启动时会注册并初始化Spring框架的所有基础组件,这些组件不仅在IOC模块中被用到,也会被AOP等模块使用。因而熟悉IOC容器的启动流程不仅是掌握IOC模块的关键,也是理解整个Spring框架的前提。
-
2.Spring是个很灵活的框架,允许用户在原有功能上进行扩展或者进行满足业务需求的个性化设置,比如对容器和Bean的生命周期过程进行增强,进行事件监听等等。要更好的使用Spring的这些特性,必须了解其工作原理,而答案就在IOC容器的启动过程中。
-
3.Spring框架在实现时使用了大量的设计模式,体现了很多优秀的设计思想。其IOC容器的启动源码就是供开发者学习这种设计经验的绝佳样板。
长求总:为了更好的理解和使用Spring框架并从它优秀的设计和实现经验中进行学习。
1.4 如何有效的阅读源码
Spring框架经过多年的发展,随着功能特性的增加,其实现也越来越复杂和抽象,要彻底弄清楚框架实现的每一个细节并不是一件简单的事。因而,对于Spring源码的解读,不必死抠每个方法和实现细节,这样太浪费时间,毕竟对于绝大分开发者而言,阅读Spring源码并不是为了成为Spring框架的开发者,而是为了更好的理解和使用Spring框架,或者从更高的角度,学习Spring的设计经验和思想,并将其运用到自己的项目实践中。
由于Spring容器的启动流程十分冗长,内容实在太多,全部放在一篇进行讲解实在太臃肿,也十分影响阅读体验。因而采取化整为零的策略,将整个IOC容器的启动流程划分为若干个阶段,每篇只对其中一个阶段进行详细讲解,因而对于容器启动源码的解读,主要抓住以下两个要点:-
1.对容器启动流程的梳理
容器启动流程分为哪几个阶段,在每个阶段容器做了哪些工作,初始化了哪些组件,执行了哪些用户自定义的回调函数。 -
2.对设计模式和设计思想的学习
在实现这个功能时采用了哪些设计模式,遵循了哪些设计思想,这么做有哪些好处。
2. 初探IOC容器启动源码
本次源码阅读的Spring版本为4.3.10.RELEASE。
启动Spring容器,本质上是创建并初始化一个具体的容器类的过程,以常见的容器类ClassPathXmlApplicationContext为例,启动一个Spring容器可以用以下代码表示
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");尽管只有短短的一行代码,但已经创建并启动了一个Spring的IOC容器。为了后面更好的理解,先来看下ClassPathXmlApplicationContext的类继承结构

关键的几个类已经用红色箭头标注了出来。
-
AbstractApplicationContext
ApplicationContext接口的抽象实现类,能够自动检测并注册各种后置处理器(PostProcessor)和事件监听器(Listener),以模板方法模式定义了一些容器的通用方法,比如启动容器的真正方法refresh()就是在该类中定义的。 -
AbstractRefreshableApplicationContext
继承AbstractApplicationContext的抽象类。内部持有一个DefaultListableBeanFactory 的实例,使得继承AbstractRefreshableApplicationContext的Spring的应用容器内部默认有一个Spring的核心容器,那么Spring容器的一些核心功能就可以委托给内部的核心容器去完成。AbstractRefreshableApplicationContext在内部定义了创建,销毁以及刷新核心容器BeanFactory的方法。 -
ClassPathXmlApplicationContext
最常用的Spring的应用容器之一。在启动时会加载类路径下的xml文件作为容器的配置信息。
下面就正式开始容器启动流程的源码阅读
进入ClassPathXmlApplicationContext的构造方法,首先调用了重载构造函数/** * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */ public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); }这里有两点需要注意下:
- 1.创建ClassPathXmlApplicationContext时需要指定xml文件的路径作为参数,尽管我们在创建时只指定了一个,但其实可以同时指定多个。
- 2.Spring容器有父子容器的概念,通过HierarchicalBeanFactory接口定义了具有层级关系的容器体系。而在抽象实现类AbstractApplicationContext类的内部,有一个表示父容器的成员变量
/** Parent context */ private ApplicationContext parent;重载函数的第三个参数即表示要创建的ClassPathXmlApplicationContext的父容器,不过这里只需要设置为null。关于Spring的父子容器,还有一些独特的访问规则,子容器可以访问父容器中的Bean,父容器不可以访问子容器中的Bean。不知道这个规则在使用Spring做web开发时可能会碰到一些匪夷所思的问题。
继续跟进源码
//设置父容器 super(parent); //设置xml文件的路径参数 setConfigLocations(configLocations); if (refresh) { //默认为true //启动Spring容器 refresh(); }设置完父容器和xml文件的路径信息后,终于看到了refresh()方法,正如前面提到的,这是真正启动Spring容器的方法,想要知道Spring IOC容器的启动流程,就要知道该方法内部都做了什么。
-
