一、下面看下普通Bean循环依赖,怎么解决
案例:A依赖B,B依赖A
1、A先实例化,同时把A放到三级缓存中,在初始化A对象里面的属性,发现有依赖B
2、创建实例B, 再把B放到三级缓存中,发现B又依赖A,执行属性填充也就是populateBean方法,里面会调用getSingleton方法
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//一级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//从三级缓存中拿
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
3、依次从存缓冲去获取A,其中一级、二级缓存中都没有,在从三级缓存中取,发现有,从三级缓存中取出,注意类型是ObjectFactory,然后调用getObject()方法
![](https://i-blog.csdnimg.cn/blog_migrate/8ef315637396e4bfcd3f0b2188f03d42.png)
getObject实际调用的是getEarlyBeanReference方法
![](https://i-blog.csdnimg.cn/blog_migrate/f741c3b36680b8aceaa751514f865ead.png)
getEarlyBeanReference里面通过,拿到BeanPostProcess判断是否是SmartInstantiationAwareBeanPostProcessor类型,如果是调用getEarlyBeanReference方法
![](https://i-blog.csdnimg.cn/blog_migrate/2d601b57bbd6cd94775a140e8982d26b.png)
最终会吧beanName加到earlyProxyReferences里面,调用wrapIfNecessary方法,该方法会判断这个bean是否是被切面处理,如果不是返回原始实例的Bean
![](https://i-blog.csdnimg.cn/blog_migrate/274757e4c38c2956353920d5a1eeb450.png)
为什么要添加到earlyProxyReferences里面去?因为对于AOP在执行AnnotationAwareAspectJAutoProxyCreator的后置处理器的时候,也会创建代理对象,这里就是为了防止重复创建,通过earlyProxyReferences缓存保存状态,如果创建过代理对象就存入earlyProxyReferences里面去。
![](https://i-blog.csdnimg.cn/blog_migrate/94cc825a32080a95a281b426edb69bd6.png)
4、调用完了后,已经拿到了AService的实例对象,但是此时的AService还没有初始化属性,是个半成品,在把AServcie存入二级缓存,同时清除三级缓存。(面试会问可不可以不要二级缓存,如果没有二级缓存这个AService因为没有完全实例化好,必须得放到二级缓存)
5、到这里BService实例已经创建好了,同时属性也赋好了值
6、把BService从三级缓存中移除,同时添加到一级缓存
7、至此BService已经到了一级缓存,而A已经从三级缓存转到了二级缓存(步骤4)
8、此时AService的属性初始化也完成了
![](https://i-blog.csdnimg.cn/blog_migrate/c4e1c6079adb43e8e4de08d7049ed783.png)
9、在调用一次getSingleton方法,因为前面我们把A从三级缓存转到了二级缓存,所以调用getSingleton方法时allowEarlyReference传的是false,先从一级拿再从二级里面拿,为什么还要在调用一次getSingleton方法,原因是,如果Bean是AOP代理,那么二级存的就是已经生成好的代理,而这个生成好的代理对象,已经被BService地址引用了,所以必须返回引用对象,才能保证AService实例在两边是一个东西。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
//allowEarlyReference传的是false,不在从三级缓存中拿
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
问题:
![](https://i-blog.csdnimg.cn/blog_migrate/d32fec2686fcd3c2eb5866fdea35a233.png)
上面有个问题:
//1、先实例化AService
exposedObject = initializeBean(beanName, exposedObject, mbd);
//2、然后又从二级缓存中拿到了AService,在返回
Object earlySingletonReference = getSingleton(beanName, false);
既然二级缓存中已经有了,那么步骤1是不是有点多余了,其实不是的,我们先看
1、如果循环依赖都是普通的Bean首先,普通实例Bean和initializeBean方法返回的exposedObject是一个对象,包括二级缓存中拿到的earlySingletonReference都是一个地址
2、如果是AOP代理的Bean,那么二级缓存中拿到的Bean,是通过BService调用了AService的getEarlyBeanReference方法生成了代理Bean,为什么这么说,因为一开始实例化A的时候,已经吧AService的ObjectFactory存到了三级缓存中,而BService在处理依赖属性的时候,就调用了ObjectFactory的getEarlyBeanReference方法,来得到代理对象,最后由BService把A的代理对象Bean,存到了二级缓存中,所以在调用initializeBean方法,会返回代理对象,但是要注意,initializeBean创建代理对象走的是postProcessAfterInitialization方法,此时earlyProxyReferences里面是包含了AService,就不会在调用wrapIfNecessary方法。这样返回的Bean还是普通实例化的Bean
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
我们在看下ObjectFactory的getObject方法
if (earlySingletonExposure) {
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
上面这2个方法都是通过wrapIfNecessary来创建代理对象,postProcessAfterInitialization创建代理对象是由AService调用initializeBean方法触发的,getEarlyBeanReference方法是BService在初始化内部属性时,调用AService的ObjectFactory.getObject()触发的,且BService顺序在initializeBean之前,所以先执行,同时把BeanName计入缓存earlyProxyReferences中,这个很重要,当initializeBean调用postProcessAfterInitialization创建代理Bean的时候,会先从缓存里面读,发现AService代理对象已经创建好了,就不会在创建了。所以无论如何AService也不会触发多次创建。(一定要理解这段话)
![](https://i-blog.csdnimg.cn/blog_migrate/50b4d24fd2663530fb17ccbe8740be6d.png)
上图又有一个疑问:AService在实例化的时候,会调用populateBean完成属性填充,此时填充的是A的普通实例对象,B创建的AService实例对象是代理对象,最后返回的也是A的代理对象,我们后面调用都是用的代理对象,而A的代理对象也没有完成属性填充,populateBean填充属性填充的操作对象,是普通实例对象,是不是填充了寂寞?
解答:其实不是,在spring的AOP代理对象属性填充,填充的就是普通实例Bean,而且这个普通实例Bean我们是要用到的,创建AOP代理Bean时,是要传普通实例Bean
![](https://i-blog.csdnimg.cn/blog_migrate/42c32c3e810b3deafd2c8e7214a700f2.png)
以JDK代理为例,执行目标方法时,还是通过我们上面创建的普通Bean,来调用的
![](https://i-blog.csdnimg.cn/blog_migrate/ae1aae6fc8b71633da46576eedc43eee.png)
![](https://i-blog.csdnimg.cn/blog_migrate/429ba56358fa26f4e366545f5e4fe2fd.png)