SpringIOC工作流程
总阅读次
IOC简介
IOC(Inverse Of Control,控制反转)是Spring容器的核心,AOP、声明式事物都是基于该功能。Spring IOC装配好Bean,并建立Bean和Bean之间的关联关系。
运行环境
- OS:win8.1
- idea:IntelliJ IDEA 2017
- java version:1.8.0_91 b4 bit
- 参考资料:《Spring4.x++企业应用开发实战》,《深入分析Java Web技术内幕》
- 使用的pom:
|
|
内部工作机制
我们通过如下方式加载Spring的配置文件,创建IOC容器
|
|
我们进入源码发现,ClassPathXmlApplicationContext
类的构造方法最终调用的就是org.springframework.context.support.AbstractApplicationContext#refresh
方法,该方法清楚的描绘了Spring容器启动所执行的各项操作
|
|
IOC流水线
Spring协调多个组件完成该复杂的流程,如下图描述了Spring容器从加载配置文件到创建一个完整Bean的流程和参与类。
ResourceLoader
从存储位置加载spring配置文件到Resource对象,这个时候Resource对象就表示该spring配置文件BeanDefinitionReader
通过Resource对象解析配置文件,将每一个<bean>
标签解析为一个BeanDefinition
对象,并保存到BeanDefinitionRegistry
对象中,这个时候的BeanDefinition
对象是没有进行加工的- 容器扫描
BeanDefinitionRegistry
对象中的BeanDefinition
对象,通过Java反射机制自动识别出实现了BeanFactoryPostProcessor
接口的bean,然后调用这个处理器对BeanDefinitionRegistry
中的BeanDefinition
进行加工处理。主要完成下面两个任务:- 对使用占位符的
<bean>
元素标签进行解析,并得到最终的值 - 对
BeanDefinitionRegistry
中定义的BeanDefinition
通过反射机制找出所有属性编辑器Bean,并自动将它们注册到Spring容器的属性编辑器注册表中
- 对使用占位符的
- Spring容器从
BeanDefinitionRegistry
中获取加工后的bean,调用InstantiationStrategy
着手进行Bean实例化,这个时候的实例化的bean还没有进行属性设置 - 在实例化Bean时,Spring容器使用
BeanWrapper
对Bean进行封装。BeanWrapper
类提供了很多反射操作Bean的方法,结合对应bean的BeanDefinition
及容器中的属性编辑器,完成Bean属性的注入工作。 - 最后一个就是收尾工作,通过实现了
BeanPostProcessor
接口的bean对已完成属性设置工作的bean进行处理,得到一个准备就绪的Bean
总结
通过上面的描述,我们其实可以将上面的IOC的工作比作流水线,在流水线上有两个主要的工具,一个是待加工的原材料,一个加工的工具。Spring组件按照承担的角色可以分为:
- 原材料类:
Resource
、BeanDefinition
、PropertyEditor
以及最终产品bean
- 工具类:
ResourceLoader
、BeanDefinitionReader
、BeanFactoryPostProcessor
、InstantiationStrategy
、BeanWrapper
及BeanPostProcessor
材料类和工具类介绍
BeanDefinition
org.springframework.beans.factory.config.BeanDefinition
是配置文件<bean>
元素标签在容器的内部表示。<bean>
标签元素拥有class、scope、lazy-init等配置属性,BeanDefinition
则提供了相应的beanClass、scope、lazyInit属性。 BeanDefinition
类的继承结构如下图:
RootBeanDefinition
是常见的的实现类,他对应一般的 <bean>
元素标签。在Spring配置文件中可以定义父<bean>
和 子 <bean>
,父bean用RootBeanDefinition
表示,子bean用ChildBeanDefinition
表示,而没有父bean的bean则用RootBeanDefinition
表示;AbstractBeanDefinition
对两者共同的类信息进行抽取。
Spring 通过BeanDefinition
将配置文件中的<bean>
转化为容器的内部表示,并将这些BeanDefinition
注册到 BeanDefinitionRegistry
中。一般情况下,BeanDefinition
只在容器启动时加载并解析,除非容器刷新或重启,否则这些信息不会发生变化。创建BeanDefinition
主要包括如下两个步骤:
- 利用
BeanDefinitionReader
读取承载配置文件信息的Resource
对象,通过xml解析DOM对象,简单的为每一个<bean>
标签生成对应的BeanDefinition
对象。但是这个时候的BeanDefinition
还是一个半成品,还有一些占位符没有被解析出来。 - 第二步,利用容器中注册的
BeanFactoryPostProcessor
对半成品的BeanDefinition
进行处理,获得一个完整的BeanDefinition
对象。
InstantiationStrategy
org.springframework.beans.factory.support.InstantiationStrategy
负责根据BeanDefinition
对象创建一个Bean实例。InstantiationStrategy
类的继承结构如下:
SimpleInstantiationStrategy
是最常用的实例化策略,该策略利用Bean实现类的默认构造函数、带参数构造函数或者工厂方法创建Bean的实例。
CglibSubclassingInstantiationStrategy
扩展了 SimpleInstantiationStrategy
,为需要进行方法注入的Bean提供了支持。它利用CGLib类库为Bean动态生成子类。
InstantiationStrategy
只负责实例化Bean的操作,相当于Java中的new的功能,它不会参与Bean属性的设置工作。所以由InstantiationStrategy
返回的bean实际上是一个半成品的bean
BeanWrapper
org.springframework.beans.BeanWrapper
是Spring中重要的组件。BeanWrapper
相当于一个代理器,Spring委托BeanWrapper
完成Bean属性的填充工作。BeanWrapper
类的继承结构如下图:
通过上图可以看出BeanWrapper
接口有两个顶级接口PropertyAccessor
和 PropertyEditorRegistry
。PropertyAccessor
接口定义访问Bean属性的方法,而PropertyEditorRegistry
是属性编辑器的注册表,可以添加一些自定义的PropertyEditor
。所最终实现的BeanWrapperImpl
类具有:
- Bean包裹器
- 属性访问方法
- 属性编辑器注册方法
总结
对Spring的Ioc容器来说,主要有BeanFactoryPostProcessor
和 BeanPostProcessor
,它们分别在构建BeanFactory和Bean时调用。还有initializingBean
和 DisposableBean
,它们分别在Bean实例创建和销毁时调用。通过这些特定的扩展点可以实现我们个性化的需求。