本文主要是说下在使用spring时遇到了循环依赖,Spring利用三级缓存怎么解决
getBean(beanName)
doGetBean(name, null, null, false);
getSingleton(beanName)方法, 最后会通过addSingleton(beanName, singletonObject)存到一级缓存里面去
createBean(beanName, mbd, args);
doCreateBean(beanName, mbdToUse, args);
1、实例化普通对象,生成singletonFactory对象存到三级缓存里面去,任何对象都会存到三级缓存,因为后面存一级缓存的时候,都会把三级缓存里面删掉
2、填充属性,包括循环依赖
3、初始化处理,AOP代理对象,如果符合AOP逻辑,那么
4、getSingleton(false)从缓存中获取对象,为什么上面创建对象了,这里还要再次获取对象,主要是循环依赖的时候这里可能已经生成好了。
备注:singletonFactory.getObject和Bean的初始化都会经过AOP来判断一次是否需要创建代理对象,但是二者只会有一个创建代理对象,他们里面利用了一个中间earlyProxyReferences缓存,创建过就不会再创建了,这个缓存不是三级缓存别搞混了
案例1:A和B只是普通类之间的相互引用
1、A先创建普通实例,然后生成一个singletonFactory对象存到三级缓存,没有什么条件基本上都会被塞到三级缓存里面。
2、A属性填充,发现需要B
3、调用B的CreateBean,B创建普通实例,singletonFactory对象存到三级缓存,没有什么条件,都会存到三级缓存里面去。
4、B属性填充,B里面需要A,然后通过三级缓存里面找,发现有,通过getObject得到A的实例对象引用,在存到二级缓存里面去,注意这里是A的实例对象,和前面A创建的实例对象是同一个,为什么,因为getObject虽然会触发后置处理的调用,但是因为不走AOP所以,调用完后置处理器,返回的依旧是A的普通实例,而这个A的普通实例哪里来的,就是在生成singletonFactory对象时候,把一开始生成的普通对象穿进去的。
5、因为是普通实例,所以B执行后置处理器,不走AOP,返回的依旧是普通的实例
6、再把B从三级缓存中移除,存到一级缓存里面去。
7、再回到A,此时A调用getBean就可以返回B的实例对象,这个时候,B已经在1级缓存,A还在二级缓存里面。
8、A的属性填充完之后,调用初始化方法,走后置处理器,因为不是AOP所以初始化之后得到的A还是普通实例
9、在接着走getSingleton(false)方法,这个时候A已经被丢到了二级缓存,所以getSingleton也会拿到对象,但是这里拿到的对象和A一开始实例化的对象是一样的。
10、最后再把A塞到1级缓存,从二级缓存中移除。
案例2:A和B都会创建代理对象,2者相互引用。
首先需要知道,A和B都是先创建普通实例对象,然后在把A和B这个普通实例对象的属性填充好,在通过这个普通实例对象来生成代理对象,因为代理对象最终也是会拿到这个普通实例对象,调用目标具体方法。
并且,A和B的普通实例对象,里面的属性赋值,赋的是代理对象,不是普通实例对象。
1、先普通实例化A,然后生成一个singletonFactory对象存到三级缓存
2、属性填充,发现需要注入B
3、调用B的CreateBean,B创建普通实例,singletonFactory对象存到三级缓存
4、B属性填充,B里面需要引入A,调用getSingleton(A, true);因为A已经在三级缓存里面了,所以会触发A的singletonFactory.getObject方法
5、A这个时候就会通过SmartInstantiationAwareBeanPostProcessor后置处理器来创建A的代理对象,并且会把A从三级缓存中移除,A添加到二级缓存里面去。
6、B调用初始化方法,这个时候B会通过后置处理器来创建代理对象,具体哪个后置和选用注解有差异,比如@Aspect和@Async创建代理的后置处理器就不一样。此时B的实例已经变成了代理对象。
7、B在调用getSingleton(beanName, false);方法,返回Null因为穿了false,注意此时B还是三级缓存里面,A已经不在三级缓存里面了,A已经跑了二级缓存里面去了,并且A此时已经是一个代理对象了
8、最后返回B实例化好的代理对象,存到一级缓存里面,然后清空三级缓存。
9、回到A的属性填充逻辑,因为此时B已经实例化了,然后把A的属性赋好值。
10、开始触发A的初始化方法,通过后置处理器创建A的代理对象,当发现A已经在缓存earlyProxyReferences里面,说明已经创建过A的代理对象,所以就不在创建A的代理对象,此时初始化方法返回的还是A的普通实例对象。
11、A开始调用getSingleton(A, false);因为此时二级缓存已经保存了A的代理对象,将代理对象取出替换A的普通实例对象,返回A的代理对象。
12、最后将A的代理对象存到一级缓存里面去,在移除二级缓存里面的数据。
待确认:B这个类里面的属性,填充进去的是A的普通对象还是代理对象。 代理对象