Spring
Spring解决循环依赖
描述:
A引用B, B引用A, 这样就构成了循环依赖
class A{
B b;
}
class B{
A a;
}
未使用Spring的情况下: 用构造方法的方式无法解决循环依赖, 但是使用set()可以
A a = new A(new B(new A(new B(new A(new B(...)))))) // 构造方法没有办法解决循环依赖
// 普通情况下使用set()可以解决循环依赖
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
使用set()后的打印结果:
我是A
我是B
Spring解决循环依赖: 三级缓存
/**
*一级缓存:
*单例对象的缓存: beanName - bean实例, 即所谓的单例池
*表示已经经历了完整的生命周期的Bean对象
**/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
*二级缓存:
*时期的单例对象的缓存: beanName - bean实例
*表示Bean的生命周期还没走完(Bean的属性还未填充)就把这个Bean存入二级缓存中
*也就是二级缓存存的是实例化但未初始化的bean
**/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
*三级缓存:
*单例工厂的缓存: beanName - ObjectFactory
*表示存放生成bean的工厂
**/
private final Map<String, ObjectFactory<?>> singletonFactoris = new HashMap<>(16);
过程:
- A创建过程中需要B, 于是A将自己放到三级缓存里面, 然后去实例化B
- B实例化的时候发现需要A, 于是B先查一级缓存, 没有, 再查二级缓存, 还是没有, 再三级缓存, 找到了A, 然后把三级缓存里面的这个放到二级缓存里面, 并删除三级缓存里面的A
- B顺利初始化完毕, 将自己放到一级缓存里面(此时B里面的A依然是创建状态), 然后回来接着创建A, 此时B已经创建结束, 直接从一级缓存里面拿到B, 然后完成创建, 并A自己放到一级缓存里面.
Spring为什么采用三级缓存的方式解决循环依赖?用二级缓存不可以吗?
原文链接:https://blog.csdn.net/qq_33468007/article/details/107814203
假如A和B都是被AOP增强的对象, 现在的A进行实例化, 并用A对B进行赋值, (这里的A的话是原生对象), 此时B开始创建并对A赋值, 此时, B注入的原生的A对象, B注入完成后被AOP增强, 所以B成为了代理对象, 然后A注入B的代理对象. 这里A注入完毕了, A通过AOP增强后也成为了代理对象. 这里就有很大的问题, 我们的A是代理对象, 而B注入的却是A的原生对象.
三级缓存的精妙
如果一个类是需要被增强的类,那么这个类会被提前增强,而且这里为什么会有AOP的缓存?道理也很简单,因此如果SpringAOP提前对user进行了增强,那么在依赖注入后的增强就会通过这个缓存判断是否已经被增强,这样就可以实现增强代码只实现一次,不重复增强user类,那么这就实现了注入的对象和原来的类是同一个。