前提
(1)作者技术比较差,文章写的比较随意,也可能有错误,欢迎您指出。
(2)如果您不了解Spring Bean的声明周期,那么您可以看一下文章(Bean的生命周期)或者百度其它文章,然后在回来看该文章,否则个人感觉应该看不懂
解决循环依赖
假设有一种下面的情况,A中有B,B中有A
@Data | |
public class A { | |
private B b; | |
public A() {System.out.println("A 无参构造器。。。");} | |
public void speak() {System.out.println("------AAA---------");} | |
} | |
@Data | |
public class B { | |
public B() {System.out.println("B 无参构造器。。。");} | |
private A a; | |
public void speak() {System.out.println("------BBB---------");} | |
} |
图片分析
代码分析
在创建的A的时候调用doCreateBean方法
1)调用A无参构造方法创建Bean
2)把该bean对象添加到三级缓存中(在下面的代码中有注释)
3)Bean的属性赋值,A的里面引用了B,所以此时会调用doCteateBean(B)
//AbstractAutowireCapableBeanFactory | |
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) | |
throws BeanCreationException { | |
{ | |
// Instantiate the bean. | |
BeanWrapper instanceWrapper = null; | |
if (mbd.isSingleton()) { | |
//省略 | |
} | |
if (instanceWrapper == null) { | |
//1)调用无参构造方法创建Bean | |
instanceWrapper = createBeanInstance(beanName, mbd, args); | |
} | |
final Object bean = instanceWrapper.getWrappedInstance(); | |
Class<?> beanType = instanceWrapper.getWrappedClass(); | |
if (beanType != NullBean.class) { | |
mbd.resolvedTargetType = beanType; | |
} | |
synchronized (mbd.postProcessingLock) { | |
//省略 | |
} | |
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && | |
isSingletonCurrentlyInCreation(beanName)); | |
if (earlySingletonExposure) { | |
if (logger.isTraceEnabled()) { | |
//省略 | |
} | |
//2)把该bean对象添加到三级缓存中,注意getEarlyBeanReference方法,特别有用 | |
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); | |
} | |
// Initialize the bean instance. | |
Object exposedObject = bean; | |
try { | |
//3)Bean的属性赋值 | |
populateBean(beanName, mbd, instanceWrapper); | |
//4)处理aware接口、applyBeanPostProcessorsBeforeInitialization、initMethod | |
exposedObject = initializeBean(beanName, exposedObject, mbd); | |
} | |
catch (Throwable ex) { | |
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { | |
//省略 | |
} | |
else { | |
//省略 | |
} | |
} | |
if (earlySingletonExposure) { | |
//省略 | |
} | |
// Register bean as disposable. | |
try { | |
registerDisposableBeanIfNecessary(beanName, bean, mbd); | |
} | |
catch (BeanDefinitionValidationException ex) { | |
//省略 | |
} | |
return exposedObject; | |
} | |
} |
此时在创建B的时候调用getBean(A),然后会走到下面代码的地方,从三级缓存中获取到A(B=null),返回该不完整的A的地址,然后B创建成功,然后继续创建A,然后A也创建成功。
-------------------------源码1
//DefaultSingletonBeanRegistry | |
protected Object getSingleton(String beanName, boolean allowEarlyReference) { | |
//从一级缓存中获取,即IOC容器,即完整的Bean对象 | |
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; | |
} |
循环依赖总结
(1)创建A的时候调用A的无参构造方法,然后在把得到的地址A(B=null)放入到三级缓存中,然后填充自己的属性B,也就会创建B;
(2)当创建B的时候,填充自己的属性A,从三级缓存中拿到A(B=null)地址,然后B创建成功;
(3)此时回到(1),此时拿到B,然后完善A,创建A成功。
(4)因为在(2)中拿到的是A的地址,所以在(3)中完善A在B中是一个。
三级缓存
疑问
个人感觉二级缓存足矣,为什么还要三级缓存?
反驳疑问
假设下面的场景:只有singletonObject(第一级缓存)和singletonFactory (第三级缓存),即没有earlySingletonObjects(第二级缓存)
如果有这么一种情况A(B),B(A),还有一个AOP是关注A的某个方法
此时的逻辑为:
1)创建A
2)把A(B=null)的地址(abc)存入singletonFactory缓存中
3)创建B
4)B在赋值a属性的时候,在singletonFactory缓存中拿出A的地址(abc)并且赋值给属性a(左边这句话是错的)(这就是三级缓存的关键),
4.1)没有AOP的时候,确实是存的a的地址,没错,返回的也是a的地址。
4.2)如果有AOP,确实存进去的是a的地址,但是返回的已经不是A的地址了,是A的代理对象地址(看源码2,3,4)。
总结:此时就出现问题了,如果没有earlySingletonObjects(第二级缓存),那么每次在singletonFactory (第三级缓存)中拿到的A对象都会创建创建一个代理对象,即每次向依赖A的对象中赋的值都是不同的代理对象,那么就不符合单例模式了。
-------------------------源码2
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; | |
} |
-------------------------源码3
//AbstractAutoProxyCreator | |
public Object getEarlyBeanReference(Object bean, String beanName) { | |
Object cacheKey = getCacheKey(bean.getClass(), beanName); | |
this.earlyProxyReferences.put(cacheKey, bean); | |
//跟进去 | |
return wrapIfNecessary(bean, beanName, cacheKey); | |
} |
-------------------------源码4
//AbstractAutoProxyCreator | |
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { | |
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { | |
return bean; | |
} | |
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { | |
return bean; | |
} | |
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { | |
this.advisedBeans.put(cacheKey, Boolean.FALSE); | |
return bean; | |
} | |
// Create proxy if we have advice. | |
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); | |
if (specificInterceptors != DO_NOT_PROXY) { | |
this.advisedBeans.put(cacheKey, Boolean.TRUE); | |
//返回了一个新对象,新地址 | |
//返回了一个新对象,新地址 | |
//返回了一个新对象,新地址 | |
Object proxy = createProxy( | |
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); | |
this.proxyTypes.put(cacheKey, proxy.getClass()); | |
return proxy; | |
} | |
this.advisedBeans.put(cacheKey, Boolean.FALSE); | |
return bean; | |
} |
总结
1)在没有AOP的情况下二级缓存足矣解决循环依赖,三级缓存更能解决问题。
2)三级缓存其实也是解决循环依赖的,是解决带AOP的循环依赖的,如上文中举的例子。如果您查的三级缓存资料没有说AOP,个人感觉这篇文章写的不是很充实。
本文没有回答的疑问
疑问1
上问中反驳二级缓存不能解决带AOP的循环依赖问题时,是把earlySingletonObjects(第二级缓存)去掉;如果我说我去掉singletonFactory (第三级缓存),那该如何反驳二级缓存不能解决带AOP的循环依赖问题呢???
疑问2
就拿上问中举的例字来说,A依赖B,B依赖A,有一个关注A的AOP。
下面是创建Bean声明周期的一段代码,以创建A为例
//AbstractAutowireCapableBeanFactory | |
protected Object doCreateBean{ | |
//创建A | |
Object exposedObject = bean; | |
try { | |
//初始化A,因为A中有属性B,此时去创建B,然后把A的代理对象存入earlySingletonObjects缓存中,B创建完毕,然后又回到此处继续初始化A | |
populateBean(beanName, mbd, instanceWrapper); | |
//为非代理对象A执行aware接口等等 | |
exposedObject = initializeBean(beanName, exposedObject, mbd); | |
} | |
catch (Throwable ex) { | |
//省略 | |
} | |
} | |
if (earlySingletonExposure) { | |
//在earlySingletonObjects中拿到代理对象A | |
Object earlySingletonReference = getSingleton(beanName, false); | |
if (earlySingletonReference != null) { | |
if (exposedObject == bean) { | |
//把exposedObject由指向非代理对象A变为指向代理对象A,那么 | |
//exposedObject = initializeBean(beanName, exposedObject, mbd); | |
//我认为是白做了,我不清楚这个地方??????????????? | |
exposedObject = earlySingletonReference; | |
} | |
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { | |
String[] dependentBeans = getDependentBeans(beanName); | |
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); | |
for (String dependentBean : dependentBeans) { | |
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { | |
actualDependentBeans.add(dependentBean); | |
} | |
} | |
if (!actualDependentBeans.isEmpty()) { | |
throw new BeanCurrentlyInCreationException(beanName, | |
"Bean with name '" + beanName + "' has been injected into other beans [" + | |
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + | |
"] in its raw version as part of a circular reference, but has eventually been " + | |
"wrapped. This means that said other beans do not use the final version of the " + | |
"bean. This is often the result of over-eager type matching - consider using " + | |
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); | |
} | |
} | |
} | |
} |