Spring使用三级缓存,分别是singletonObjects,earlySingletonObjects,singletonFactories来解决循环依赖问题。但是用二级缓存就可以解决循环依赖了。为什么要使用三级缓存呢?因为有动态代理。必须保证单例bean在bean工厂中只有一个对象。所以提供了singletonFactories用lamada表达式用来将代理后的对象替换被代理对象。保证有动态代理bean工厂也只有一个单例bean。
一、修改为二级缓存
修改DefaultSingletonBeanRegistry.getSingleton(String beanName, boolean allowEarlyReference),注释原来的这个函数,复制一份改为:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object 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 lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
}
}
}
}
return singletonObject;
}
在DefaultSingletonBeanRegistry类新增以下方法:
protected void addearlySingletonObjects(String beanName, Object object) {
Assert.notNull(object, "Singleton bean must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.earlySingletonObjects.put(beanName,object);
this.registeredSingletons.add(beanName);
}
}
}
注释AbstractAutowireCapableBeanFactory.doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法里面的addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));这行代码,在下面新增:
addearlySingletonObjects(beanName,bean);
在没有动态代理时可验证可解决循环依赖。
现在加上动态代理:
Logger.java
public class Logger {
public void dothing() {
System.out.println("现在时间是:"+ DateFormat.getDateInstance().format(new Date()));
}
}
circle.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="a" class="circle.A">
<property name="b" ref="b"/>
</bean>
<bean id="b" class="circle.B">
<property name="a" ref="a"/>
</bean>
<bean id="logger" class="circle.Logger"/>
<aop:config>
<aop:aspect id="logger" ref="logger">
<aop:pointcut expression="execution(* circle.*.*(..))" id="method" />
<aop:before method="dothing" pointcut-ref="method" />
</aop:aspect>
</aop:config>
</beans>
调试可知:
新建a,调用AbstractAutowireCapableBeanFactory.doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)调用createBeanInstance(beanName, mbd, args)实例化a,调用populateBean(beanName, mbd, instanceWrapper)填充a的属性b,populateBean调用applyPropertyValues(beanName, mbd, bw, pvs)填充属性,applyPropertyValues又调用valueResolver.resolveValueIfNecessary(pv, originalValue)解析获取b,resolveValueIfNecessary通过resolveReference,resolveReference通过beanFactory.getBean(resolvedName)获取b,经过b的实例化和从earlySingletonObjects中获取属性a完成了b的创建和属性填充。在调用populateBean后,调用initializeBean(beanName, exposedObject, mbd)生成了b的代理对象并在DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)通过addSingleton(String beanName, Object singletonObject)将b放入singletonObjects
。返回填充a的属性b后:
通过initializeBean(beanName, exposedObject, mbd)生成a的代理,而earlySingletonObjects保存的a是A@2397,即bean,生成a的代理对象是circle.A@769a1df5,即exposedObject,AbstractAutowireCapableBeanFactory.doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)调用
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
导致exposedObject == bean为false,有两个不同的bean而抛出无法解决循环依赖的异常。
Exception in thread "main" org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] 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 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
标签:缓存,String,mbd,Spring,beanName,Object,bean,源码,singletonObject From: https://www.cnblogs.com/shigongp/p/16756416.html