Spring: IoC实现

IoC容器

Spring中有两个主要的容器系列:BeanFactoryApplicationContext

  • BeanFactory: 定义了IoC容器的基本功能。

  • ApplicationContext: 在简单容器的基础上,通过继承MessageSourceResourceLoaderApplicationEventPublisher等接口增加了许多面向框架的特性。

Spring通过定义BeanDefinition来管理各种Bean以及它们之间的依赖关系,是对它们的抽象,是IoC容器的核心数据结构。

BeanFactory容器原理

在Spring中默认把DefaultListableBeanFactory作为一个功能完整的IoC容器。

编程式使用IoC容器
1
2
3
4
5
6
7
8
ClassPathResource res = new ClassPathResource("spring-beans.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
readr.loadBeanDefinitions(res);

Spring中使用Resource来封装BeanDefinition的信息源(XML文件),IoC容器通过Resource来定位BeanDefinition的信息,从而完成容器的初始化和依赖注入过程。

通过调用XmlBeanDefinitionReaderloadDefinitions()方法从Resource中开始载入BeanDefinition

ApplicationContext容器原理

ApplicationContext容器扩展了MessageSource接口,可以支持国际化的实现,开发多语言版本;具体的ApplicationContext实现都是继承了DefaultResourceLoader的子类,可以从不同的地方得到BeanDefinition的资源;同时还继承了ApplicationEventPublisher接口,从而在应用上下文中引入了事件机制,这些事件机制和Bean的生命周期的结合为Bean的管理提供了便利。

ApplicationContext是通过refresh()方法来启动IoC容器的,同时还会对BeanDefinition的信息源进行封装成Resource(例如 ClassPathResource、FileSystemResource等)。

IoC容器的初始化

IoC容器的初始化分为3个过程:

  1. Resource 的定位过程,即BeanDefinition的资源定位。

  2. BeanDefinition 的载入和解析。

  3. BeanDefinition 在IoC容器中的注册。

XML -> Resource -> Document -> BeanDefinition

Resource定位

使用DefaultListableBeanFactory时,需要自己去定位Resource,并提供相应的BeanDefinitionReader来对这些信息进行处理。DefaultListableFactory是一个纯粹的IoC容器。

而在ApplicationContext中已经提供了一系列Resource定位的实现以及BeanDefinitionReader

BeanDefinition的载入和解析

IoC容器的载入过程,是把定义的Bean转化成Spring内部表示的数据结构(BeanDefinition)的过程。

BeanDefinition载入分为两部分,首先通过调用XML的解析器得到Document对象,然后通过DocumentReader完成对Document对象的解析(按照Spring的Bean规则,默认是使用DefaultBeanDefinitionDocumentReader)。

DefaultBeanDefinitionDocumentReader中通过调用BeanDefinitonParserDelegateprocessBeanDefinition()方法来实现,处理的结果是生成BeanDefinitionHolder对象持有。BeanDefinitionHolder对象除了持有BeanDefinition对象外,还有其他与BeanDefinition的使用相关的信息,比如 Bean 的名字、别名集合等。

BeanDefinition在IoC容器中的注册

通过对BeanDefinition的载入和解析过程,在IoC容器内已经建立相应的数据结构和数据表示,但是这些数据还不能供IoC容器直接使用,需要对这些BeanDefinition对象进行注册。

IoC容器中通过一个ConcurrentHashMap来保持和维护这些加载的BeanDefinition

注册完,整个IoC容器的初始化就完成了。

IoC容器的依赖注入

依赖注入的过程是在用户第一次向IoC容器索要 Bean 时触发的,也可以通过设置lazy-init=false属性让容器完成对 Bean 的预实例化(其实也是一个完成依赖注入的过程)。

触发依赖注入的入口在BeanFactory提供的getBean()方法中。具体的依赖注入发生时在BeanWrapper的实现类BeanWrapperImplsetPropertyValue()方法中实现。

在Bean的创建和对象依赖注入的过程中,需要根据BeanDefinition中的信息递归的完成。一个递归是在上下文中查找需要的Bean和创建Bean的递归调用。另一个递归是在依赖注入时,通过递归调用容器的getBean()方法,得到当前Bean依赖的Bean,同时也触发对依赖Bean的创建和注入。

Bean的生命周期

  1. Bean实例的创建

  2. 为Bean实例设置属性

  3. 调用Bean的初始化方法

  4. 应用Bean

  5. 容器关闭时调用Bean的销毁方法。