Spring-循环依赖简述

什么是循环依赖

// A依赖了B
class A
{
    public B b;
}
​
// B依赖了A
class B
{
    public A a;
}
​
// 循环依赖
A a = new A();
B b = new B();
a.b = b;
b.a = a;

对象之间的相互依赖很正常,但是在Spring中由于对象创建要经过Bean的生命周期,所以就有了循环依赖问题

Bean的生命周期

在Spring中,被Spring管理的对象叫做Bean,那么Bean是如何生成的?

1、Spring扫描class得到BeanDefinition,放在一个Map里

2、根据得到的BeanDefinition去生成Bean

3、首先根据class推断构造方法

4、根据推断出来的构造方法,反射得到一个对象

5、填充原始对象中的属性,依赖注入

6、如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象

7、把最终生成的代理对象放入单例池中,下次getBean直接从单例池拿即可

这里只列举出大致流程,还有Aware回调、初始化等

出现循环依赖的流程简述:

ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在 创建过程中)

在Spring中,就是通过三级缓存机制解决的循环依赖问题

三级缓存

一级缓存为:singletonObjects;二级缓存为:earlySingletonObjects;三级缓存为:singletonFactories

三个缓存的作用:

  • singletonObjects中缓存的是已经经历了完整生命周期的bean对象。

  • earlySingletonObjects比singletonObjects多了一个early,表示缓存的是早期的bean对象。也就是Bean的生命周期还没走完就把这个Bean放入了earlySingletonObjects。

  • singletonFactories中缓存的是ObjectFactory,表示对象工厂,表示用来创建早期bean对象的工厂。

循环依赖问题:A创建时--->需要B---->B去创建--->需要A,从而产生了循环

打破循环依赖,可以加个中间人(缓存)

Spring-循环依赖简述_第1张图片

一个缓存就能解决循环依赖了,那么为什么Spring中还需要singletonFactories呢?

如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象,此时对于A而言,它的Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突。B依赖的A和最终的A不是同一个对象

现在Spring所用的singletonFactories,为了调和不同的情况,在singletonFactories中存的是lambda表达式,这样的话,只有在出现了循环依赖的情况,才会执行lambda表达式,才会进行AOP,也就说只有在出现了循环依赖的情况下才会打破Bean生命周期的设计,如果一个Bean没有出现循环依赖,那么它还是遵守了Bean的生命周期的设计的。

singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory是一个函数式接口,所以支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd, bean)

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}
​
// InstantiationAwareBeanPostProcessorAdapter
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    return bean;
}
​
// AbstractAutoProxyCreator(AnnotationAwareAspectJAutoProxyCreator的父类,进行AOP用到)
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    this.earlyProxyReferences.put(cacheKey, bean);
    return wrapIfNecessary(bean, beanName, cacheKey);
}

总结

1、singletonObjects:缓存经过了完整生命周期的bean

2、earlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects

3、singletonFactories:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖,则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存。

4、还有一个缓存,就是earlyProxyReferences,用来记录某个原始对象是否进行过AOP了。在AbstractAutoProxyCreator的postProcessAfterInitialization方法中,会去判断当前beanName是否在earlyProxyReferences,如果在则表示已经提前进行过AOP了,无需再次进行AOP。

思考:为什么需要singletonFactories?假设没有singletonFactories,只有earlySingletonObjects会怎样?

你可能感兴趣的:(spring,java)