一、回顾下 bean的创建过程
二、构造器注入的循环依赖
1、先创建两个循环依赖的类
public class ServiceA{private ServiceB b;// 构造方法public ServiceA(ServiceB b){this.b = b;}}public class ServiceB{private ServiceA a;// 构造方法public ServiceB(ServiceA a){this.a = a;}}
2、然后 main 函数中调用,发现该依赖无法解决
new ServiceA(new ServiceB(new ServiceA(.......)))
三、Set 方式注入
设置两个循环依赖的类
public class ServiceBB{private ServiceAA aa;// set方法public void setServiceAA(ServiceAA serviceAA){this.aa = serviceAA;}}public class ServiceAA{private ServiceBB bb;// set方法public void setServiceBB(ServiceBB servicebb){this.bb = servicebb;}}
然后main函数调用,set可以解决循环调用,因为new的时候是调用一个空的无参构造方法,此时并没有依赖。
原因是 spring 内部用到了 三级缓存 解决这个问题。
public class test{public static void main(String[] args){ServiceAA a = new ServiceAA();ServiceBB b = new ServiceBB();b.setServiceAA(a);a.setServiceBB(b);}}
四、三级缓存
1、简单介绍
在实例化的过程中,将处于半成品的对象全部都放到缓存中,方便后续来进行调用,只要有了当前对象的引用地址,那么后续来进行赋值也可以。 半成品对象放到了map缓存结构中,成品对象要不要也放到某一个map中,能否把成品和半成品对象放到一起?如果放到一起,就会导致获取对象的时候获取到半成品对象,值为空。 为了将成品和半成品对象完全的区分开,那么可以创建两个缓存对象,即两个map,当然还有第三个map,这就是三级缓存。 一级:成品对象 二级:半成品对象 三级:?为什么需要这个三级缓存
2、三级缓存代码位置

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {/** Cache of singleton objects: bean name to bean instance. */// 一级// 单例池:存放了已经经历了完整生命周期的bean对象,即已经初始化好的bean,也就是所谓的单例池private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */// 三级 存放可以生成Bean的工厂,存放FactoryBean。假如A类实现了FactoryBean,那么依赖注入的时候不是A类,而是A类产生的Beanprivate final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */// 二级// 存放早期暴露出来的bean对象,Bean的生命周期未结束(属性还没有填充完整),即存放的是实例化一半的beanprivate final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
DefaultListableBeanFactory#preInstantiateSingletons —》 getbean—>doGetBean—>如下代码

Object singletonObject = this.singletonObjects.get(beanName);// 如果一级缓存为空,则执行如下代码if (singletonObject == null) {
继续走下去,从传进的 singletonFactory 中获取 getObject
我们看看传进来的 singletonFactory 是什么,如下,是个 Lambda表达式,进入 createBean
—》doCreateBean
然后看到这个方法里面调用了 addSingletonFactory 方法。
addSingletonFactory 方法如下
/*** Add the given singleton factory for building the specified singleton* if necessary.* <p>To be called for eager registration of singletons, e.g. to be able to* resolve circular references.* @param beanName the name of the bean* @param singletonFactory the factory for the singleton object*/protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");// 使用 singletonOjects 加锁,保证线程安全synchronized (this.singletonObjects) {//如果一级单例对象的高速缓存map【bean名称->bean实例】没有beanName的对象if (!this.singletonObjects.containsKey(beanName)) {// 将 beanname,singletonFactory 放到单例工厂的缓存(三级)【bean名称 - ObjectFactory】this.singletonFactories.put(beanName, singletonFactory);// 将二级单例对象的高速缓存【bean名称->bean实例】释放beanName的相关缓存this.earlySingletonObjects.remove(beanName);// 将 beanName 添加到已注册的单例集合中this.registeredSingletons.add(beanName);}}}
(populateBean)接着进行bean属性的填充,或者可能依赖于其他bean 的属性的,则会递归初始化依赖的bean
populateBean—》applyPropertyValues—》 valueResolver.resolveValueIfNecessary—》resolveReference—》 this.beanFactory.getBean —》doGetBean —》Object sharedInstance = getSingleton(beanName);
�注意:这次的 getSingleton,和上面的 getSingleton不一样,这个的没有 lambda方法,

@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);// 正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 从二级缓存里面取singletonObject = this.earlySingletonObjects.get(beanName);// 二级缓存中没有,并且允许创建二级缓存if (singletonObject == null && allowEarlyReference) {// 锁定全局变量进行处理synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {// 当某些方法需要提前初始化的时候则会调用 addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonfactories里面// 三级缓存中取ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 如果存在单例工厂,则通过工厂创建一个单例对象singletonObject = singletonFactory.getObject();// 记录在缓存中,二级缓存和三级缓存的对象不能同时存在this.earlySingletonObjects.put(beanName, singletonObject);// 移除三级缓存this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}
�。。。。。。。有空自己debug吧
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
五、疑问
1、三级缓存汇总分别保存的是什么对象
1、成品对象 2、半成品对象 3、lambda表达式
2、如果只使用1级缓存行不行?
不行,因为成品和半成品对象会放到一起,在进行对象获取的时候有可能会获取到半成品对象,这样的对象是没办法使用的。
3、如果只有二级缓存,将三级缓存去掉 行不行?
getSingleton、doCreateBean 中用到了二级缓存 只有二级缓存的时候,也可以解决循环依赖问题。
但是AOP就不能用了。会报错 this mean that said other beans do not use the final version of the bean ,没有使用最终版本的bean对象
4、三级缓存存在到底是干什么用的?
如果一个对象需要被代理,生成代理对象,那么这个对象需要预先生产非代理对象吗? 需要
三级缓存到底干了什么? lamdba.getEarlyBeanReference(),只要搞清楚这个方法的具体执行逻辑即可。 当前方法中,有可能会用代理对象替换非代理对象,如果没有三级缓存的话,那么就可能无法得到代理对象,即在整个容器中,包含了同名对象的代理对象和非代理对象,这是不行的。 容器中,对象都是单例的,意味着根据名称只能取到一个对象的值,如果没有三级缓存,那这个代理对象就有可能存放在二级缓存中,那就可能冲突了。所以在三级缓存中完成了代理对象替换非代理对象的工作,确定返回的是唯一对象。 所以三级缓存是为了解决在 aop 代理过程中产生的循环依赖问题,如果没有 aop的话,二级缓存足以。



上图中最后返回的代理对象,会被放到三级缓存中去。


