生命周期图解
启动Spring项目顺序
实例化BeanFactoryPostProcessor,并执行postProcessBeanFactory,
可以通过BeanFactoryPostProcessor提前实现注入对象属性
实例化BeanPostProcessor,
用于初始化bean的回调
实例化InstantiationAwareBeanPostProcessorAdapter,
用于实例化bean的回调
开始注入每个bean,
注入过程,先执行InstantiationAwareBeanPostProcessor,在执行BeanPostProcessor
,按目录顺序加载
⭐注入一个bean的过程
执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation
——若构造函数中有传入对象,则先注入传入的bean
执行构造函数
——若属性有注入@Autowired的bean,则先注入属性中的bean
——若实现BeanNameAware接口,则调用BeanNameAware.setBeanName()
——若实现BeanFactoryAware接口,则调用BeanFactoryAware.setBeanFactory()
执行BeanPostProcessor的postProcessBeforeInitialization
——若有@PostConstruct注解的方法,则执行该方法
——若实现了InitializingBean接口,则调用InitializingBean.afterPropertiesSet()
——若通过@Bean指定了initMethod方法,则调用
<bean>
的init-method属性指定的初始化方法执行BeanPostProcessor的postProcessAfterInitialization
执行InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation
Spring中bean的三种初始化方法:postConstruct、afterPropertiesSet、init-method:
Spring在设置完一个bean所有的属性后,会检查bean是否实现了InitializingBean接口,如果实现就调用bean的afterPropertiesSet方法
如果一个bean同时实现了这两种方式的初始化配置,则spring会先调用afterPropertiesSet方法,然后通过反射调用init-method
通过@PostConstruct注解的方法在afterPropertiesSet和init-method方法之前调用
InstantiationAwareBeanPostProcessor和BeanPostProcessor提供了注入每个bean时的两个回调:
在BeanPostProcessor接口的实现类中注入的bean,相当于
提前注入
,不会受该类的before/after的回调的影响InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,可以在Bean生命周期的另外两个时期提供扩展的回调接口,即
实例化Bean
之前(调用postProcessBeforeInstantiation方法)和实例化Bean
之后(调用postProcessAfterInstantiation方法
如果被装配的Bean实现了相应的接口,就可以在Bean中获得相应的信息:
BeanNameAware:获得Bean名,也就是
<Bean>
标签的id属性值。BeanClassLoaderAware:获得装载过程中的ClassLoader对象。
BeanFactoryAware:获得BeanFactory对象
ApplicationContextAware:获得ApplicationContext对象
InitializingBean:在Bean的所有属性设置完后,并且在调用完上面接口的方法后,调用此接口的afterPropertiesSet方法
DisposableBean:当销毁Bean时,调用此接口的destroy方法
Spring Bean的循环依赖
什么是循环依赖
Spring Bean
的循环依赖是指,类A需要通过构造函数注入的类B的实例(或者B中声明的Bean),而类B需要通过构造函数注入的类A的实例(或者A中声明的Bean)。如果将类A和类B的bean配置为相互注入,则Spring IoC
容器会在运行时检测到此循环引用,并引发一个BeanCurrentlyInCreationException
循环依赖的三种情况
循环依赖的产生可能有很多种情况,例如:
1、A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象
2、A的构造方法中依赖了B的实例对象,同时B的某个field或者setter需要A的实例对象,以及反之
3、A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象,以及反之
Spring对于循环依赖的解决不是无条件的,首先前提条件是针对scope单例并且允许解决循环依赖的对象。
以上三种情况:
第一种Spring无法解决
第二种只能解决一部分情况
第三种可以解决
循环依赖解决方式: 三级缓存
单例bean创建流程:
1)、
AbstractBeanFactory.getBean
为入口并委托AbstractBeanFactory.doGetBean
创建2)、
AbstractBeanFactory.doGetBean
会首先从AbstractBeanFactory.getSingleton
中获取缓存的bean对象, 如果不存在则调用抽象方法createBean, 即子类实现的AbstractAutowireCapableBeanFactory.createBean
方法3)、
AbstractAutowireCapableBeanFactory.createBean
方法触发doCreateBean依次调用以下方法实现bean创建过程:createBeanInstance: 实例化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方) addSingletonFactory: 将实例化bean加入三级缓存 populateBean: 初始化bean, 如果需要依赖其他对象则首先创建其他对象(发生循环依赖的地方) initializeBean registerDisposableBeanIfNecessary
4)、
AbstractAutowireCapableBeanFactory.autowireConstructor
使用构造函数进行实例化5)、最终调用
ConstructorResolver.autowireConstructor
和ConstructorResolver.resolveConstructorArguments
进行实例化已经解析构造参数6)、调用
BeanDefinitionValueResolver.resolveValueIfNecessary
和BeanDefinitionValueResolver.resolveReference
模版类解析构造参数
在DefaultSingletonBeanRegistry
使用三级缓存:
1 | // 第一层: 初始化完备的单例bean |
解决方案
简明的说就是,不使用基于构造函数的依赖注入,可通过下面方式解决:
在字段上使用@Autowired注解,让Spring决定在合适的时机注入【推荐】
用基于setter方法的依赖注射取代基于构造函数的依赖注入来解决循环依赖