Spring IoC容器实现

1. 容器:

  • IoC容器自身Spring实现分成两个系列:
    • BeanFactory(简单):体现容器的基本功能规范
      • getBean():从容器中获取相应实例。(添加相应条件,如名字、类型、构造参数等)
      • containsBean():判断是否包含某个Bean
      • isSingleton,isPrototype:判断Bean的类型。
      • isTypeMatch():判断指定名字的Bean的Class类型是否特性的Class类型
      • getType():查询指定名字的Class类型
      • getAliases():查询指定Bean的所有别名
    • ApplicationContext应用上下文(高级):简单容器基础上,添加了框架特性,对应用环境做了适配。
      • 扩展MessageSource接口,支持国际化、多语言
      • 继承ApplicationEventPublisher接口,引入事件机制,和Bean的生命周期结合方便Bean的管理
      • 推荐使用
  • 容器管理的对象
    • BeanDefinition:抽象对Bean的定义,管理容器内的各种对象、依赖关系。

2. 容器实现设计:

IoC容器主要接口设计:

  • 第一条设计主线(以BeanFactory为核心):
    • interface BeanFactory:定义基本的容器规范,定义了一系列的接口方法,可以使用不同的bean检索方法。
    • interface HierarchicalBeanFactory extends BeanFactory:继承BeanFactory基础上,增加了getParentBeanFactory() 功能,使BeanFactory具备双亲容器的管理功能。(双亲委托模式)
    • interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry:定义了对BeanFactory的配置功能,比如设置双亲容器,配置Bean后置处理器等。(各种配置项)因为其包含双亲容器的配置,所以是继承HierarchicalBeanFactory的。
    • class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable:IoC容器简单具体实现,其他IoC容器基于该类扩展新功能实现。XMLBeanFactory、ApplicationContext等。可以作为一个默认的功能完成的IoC容器使用,XMLBeanFactory继承后,增加了部分新功能。
  • 第二条设计主线(以ApplicationContext为核心):
    • interface ListableBeanFactory extends BeanFactory:细化了许多BeanFactory的接口功能,主要是罗列bean实例的功能。
    • interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver:通过继承BeanFactory相关接口具备容器基本功能,通过继承MessageSource等接口赋予了高级容器特性支持。ApplicationContext不继承ConfigurableBeanFactory,我的理解是因为有各种高级容器特性的配置都分类在相应接口中了,和BeanFactory主线的配置设计不同,所以不继承。
  • DefaultListableBeanFactory、XMLBeanFactory、ApplicationContext等都是容器附加了某种功能的具体实现,也就是容器体系中的具体容器产品。
  • spring接口独立设计,每个接口都有其特定功能,遵循接口隔离原则

3. 容器实现设计:

容器的核心启动操作(refresh)在不同类型的容器下都是类似的,所以这部分步骤都会在基类中进行实现,具体的容器类(如下两个),只需要实现部分和它自身设计相关的功能就可(如Resource定位方式不同等)。

XmlBeanFactory

以XmlBeanFactory为例(BeanFactory基础系列,和应用上下文比只提供最基本的IoC容器功能):(读取XML文件定义BeanDefinition的IoC容器
)(@deprecated as of Spring 3.1 in favor of {@link DefaultListableBeanFactory} and {@link XmlBeanDefinitionReader})

  • Resource:定义BeanDefinition 信息来源(指定文件、xml、URL等),spring用来封装I/O操作的类。
  • XmlBeanDefinitionReader:读取器,XML信息处理,读取XML中的BeanDefinition信息
  • 构造需要的Resource,作为参数传递给BeanFactory构造函数,然后IoC容器可以定位到BeanDefinition信息来对Bean完成容器的初始化和依赖注入。
  • 初始化XmlBeanFactory需要传入Resource对象,然后使用reader.loadBeanDefinitions(resource)从resource中加载对应信息。


FileSystemXmlApplicationContext

以FileSystemXmlApplicationContext为例(ApplicationContext系列,BeanFactory基础上提供附加服务):(读取XML定义文件,但是XML文件来源定义支持URL、文件路径、多路径等,同时支持模式匹配文件名等)

  • 应用上下文主要功能已经在AbstractXmlApplicationContext中实现。FileSystemXmlApplicationContext只需要实现和它自身设计相关的两个功能。

    • 实例化上下文,启动IoC容器refresh()过程(refresh主要是IoC容器启动的操作,不同容器实现步骤都是差不多的,所以封装在基类中。)

    • 获取Resource,根据设计确定如何从文件系统中加载XML的BeanDefinition定义资源。如下是定义了FileSystemXmlApplicationContext对应的Resource获取方法。

BeanFactory 和 ApplicationContext区别
  • ApplicationContext提供了加载不同Resource的读取器(BeanDefinitionReader)的实现。 BeanFactory需要配置特定的读取器。(如上可见,BeanFactory需要配置特定的BeanDefinitionReader,而ApplicationContext则只确定Resource即可,根据不同Resource制定对应Reader的实现已经封装在基类中)

4. IoC容器初始化过程

IoC初始化是为了建立起BeanDefinition的映射进行依赖注入,该过程不涉及到依赖注入。
IoC初始化调用refresh()启动,分为三个过程:

  • BeanDefinition的Resource定位:BeanDefinition的资源定位,由ResourceLoader通过统一的Resource接口完成。Resource对各种形式的BeanDefinition的使用提供了统一接口。
  • 载入:定义好的Bean表示成IoC容器内部数据接口,也就是BeanDefinition,BeanDefinition是POJO对象在IoC容器中的抽象
  • 注册:向IoC容器注册BeanDefinition的过程,调用BeanDefinitionRegistry接口完成,使用HashMap存储BeanDefinition数据

注:refresh()不包含Bean依赖注入的实现,依赖注入发生在第一次通过getBean向容器索取Bean的时候(可通过为Bean配置lazyinit使依赖注入在初始化时完成)

4.1 BeanDefinition的Resource定位(找水源)

以FileSystemXmlApplicationContext为例:
支持XML定义BeanDefinition的ApplicationContext,指定以文件形式的BeanDefinition读入,文件可以使用文件路径和URL表示。
继承图:

FileSystemXmlApplicationContext使用DefaultListableBeanFactory作为IoC容器供ApplicationContext使用,构造器中调用refresh()方法完成容器的初始化。(refresh的方法步骤)

步骤:

  • 创建新的BeanFactory
  • 创建对应Resource的BeanDefinitionReader,其中包含对应的ResourceReader
  • BeanDefinitionReader根据传入的参数获取相应的Resource
  • 后续通过获取的Resource来进行BeanDefinition的载入
4.2 BeanDefinition的解析和载入(打水)

把定义的BeanDefinition在IoC容器中转化成一个Spring内部表示的数据结构,BeanDefinition数据在IoC容器中通过一个HashMap来保持和维护,后IoC容器根据BeanDefinition信息进行注册。

以AbstractApplicationContext#refresh 为入口,描述了ApplicationContext的初始化过程(Bean的生命周期):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 在子类中启动refreshBeanFactory()
// 创建新的BeanFactory,并从对应的Resource中load BeanDefinition存储到factory中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 设置BeanFactory的后处理器
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用BeanFactory的后处理器,这些处理器是在Bean定义中向容器注册的
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册Bean的后处理器,在Bean创建过程中调用
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 对上下文中的消息源进行初始化
initMessageSource();
// Initialize event multicaster for this context.
// 初始化上下文中的事件机制
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化其他特殊的Bean
onRefresh();
// Check for listener beans and register them.
// 检查监听Bean,并且将这些Bean向容器注入
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有的(non-lazy-init)单件
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 发布容器事件,结束refresh过程
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 为防止Bean资源占用,在异常处理时,销毁已经在前面过程中生成的单例Bean
destroyBeans();
// Reset 'active' flag.
// 重置 active 标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory) 载入BeanDefinition:过程大概就是初始化读取器(reader),在IoC容器(DefaultListableBeanFactory)中设置好该读取器,将Resource载入并传给Reader完成读取和载入。

  • 通过调用XML解析器得到document对象
  • 将document对象转换成BeanDefinition载入到IoC容器中,并在容器中建立数据映射。
4.3 BeanDefinition在IoC容器中的注册

BeanDefinition信息载入完成后,在DefaultListableBeanFactory中,使用Hashmap来存储载入的BeanDefinition(注册)。

完成了BeanDefinition的注册,就完成了IoC容器启动的初始化过程,此时BeanFactory中已经建立了所有bean的配置信息,BeanDefinition已经可以被容器使用。容器基于这些数据实现依赖反转(依赖注入)。

5. IoC容器依赖注入

依赖注入是在用户首次向容器索要Bean的时候触发的,(可以配置lazy-init让容器对Bean预初始化),在调用BeanFactory.getBean() 时触发。

大体流程:

  • 从单例bean缓存中尝试获取bean,如果存在已创建过的bean,则返回该bean
  • 如果当前BeanFactory中不存在beanName匹配的BeanDefinition,则递归去parentBeanFactory中查找
  • 获取到对应的BeanDefinition,递归实例化依赖的bean
  • 根据当前bean的scope,创建Singleton(单例)或prototype(原型) 或其他类型的bean实例
  • 对创建的Bean进行类型检查,无误则返回。

6. 容器其他相关特性的设计和实现

6.1 ApplicationContext和Bean的初始化和销毁

IoC容器的初始化(prepareBeanFactory)在BeanFactory创建完成并加载完BeanDefinition后进行。spring IoC容器提供了相关的功能,可以让应用定制Bean的初始化和销毁过程。

Bean的简单生命周期:

  • Bean实例的创建
  • 为Bean实例设置属性
  • 调用Bean的初始化方法
  • 应用可以通过IoC容器使用Bean
  • 当容器关闭时,调用Bean的销毁方法。

Bean初始化过程:

  • 调用一系列的aware接口,把相关的BeanName、BeanClassLoader/BeanFactory注入到Bean中
  • 如果Bean实现了InitializingBean接口,则对Bean进行回调,调用afterPropertiesSet方法
  • 调用Bean配置的initMethod方法

Bean销毁过程:

  • 调用postProcessBeforeDestruction
  • 调用Bean的destroy方法
  • 调用Bean自定义销毁方法
6.2 lazy-init属性和预实例化

在refresh过程中,调用了一把getBean实现…

6.3 FactoryBean的实现

FactoryBean为应用生成需要的对象,这些对象同一般的bean不同,需要经过特殊处理,如ProxyFactoryBean等。在getBean中对应FactoryBean使用其getObject方法获取对象实例。

Factory提供了很好的封装机制。

工厂模式简介:

6.4 BeanPostProcessor的实现

后置处理器在Bean实例化后,初始化前后(AbstractAutowireCapableBeanFactory#invokeInitMethods)提供回调入口,进行相关操作。

6.5 autowiring(自动依赖装配)的实现

配置好autowiring属性,IoC容器会根据属性反射自动查找属性的类型或名字,然后根据属性的类型或名字来自动匹配IoC容器中的Bean,自动完成依赖注入。

在执行依赖注入时(AbstractAutowireCapableBeanFactory#populateBean),处理一般Bean之前,先对autowiring属性进行处理。根据Bean的属性名,执行getBean索取Bean,然后创建PropertyValues用于后续实例化Bean时的属性填充。

6.6 Bean的依赖检查???

AbstractAutowireCapableBeanFactory#checkDependencies
在Bean定义中设置dependency-check属性指定依赖检查模式??

Bean对IoC容器的感知

实际使用场景???
在Bean中直接对IoC容器进行操作,需要在Bean中设定对容器的感知,通过特定的aware接口完成。在设置Bean的属性之后,调用初始化回调方法之前(initializeBean中),Spring会调用aware接口中的setter方法,是相应信息在Bean中保存下来。