spring 技术内幕 - 笔记(1)- IoC容器实现
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的管理
- 推荐使用
- BeanFactory(简单):体现容器的基本功能规范
- 容器管理的对象
- 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的生命周期):
|
|
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中保存下来。