SpringBean的生命周期

生命周期图解

Bean的生命周期1
Bean的生命周期2

启动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.autowireConstructorConstructorResolver.resolveConstructorArguments进行实例化已经解析构造参数

  • 6)、调用BeanDefinitionValueResolver.resolveValueIfNecessaryBeanDefinitionValueResolver.resolveReference模版类解析构造参数

DefaultSingletonBeanRegistry使用三级缓存:

1
2
3
4
5
6
7
8
9
// 第一层: 初始化完备的单例bean
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 第二层: 提前暴光的单例对象的Cache
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 第三层: ObjectFactory工厂bean缓存, 存储实例话后的bean Factory
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

解决方案

简明的说就是,不使用基于构造函数的依赖注入,可通过下面方式解决:

  • 在字段上使用@Autowired注解,让Spring决定在合适的时机注入【推荐】

  • 用基于setter方法的依赖注射取代基于构造函数的依赖注入来解决循环依赖

参考文献: