Spring三級緩存解決循環依賴
三級緩存的定義
答案就在DefaultSingletonBeanRegistry的注釋里面
.....
/**
* 一級緩存 存放完全初始化好的對象, 拿來可以直接使用
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 二級緩存 存放還未完成初始化好的對象, 從三級緩存拿出后,放到二級里面
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
* 三級緩存 存放beanName-> ObjectFactory的匿名內部類
* 何時添加三級緩存:DefaultSingletonBeanRegistry#addSingletonFactory(java.lang.String, org.springframework.beans.factory.ObjectFactory)
* 匿名干的事兒:AbstractAutowireCapableBeanFactory#getEarlyBeanReference(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object)
* 解決代理對象的問題
* A 依賴 B,把A的ObjectFactory匿名內部類放到三級緩存
* 創建B,B依賴A,從三級緩存拿到匿名內部類,然后調用getObject方法,如果A是簡單普通對象,直接返回a, 如果A需要代理,則返回代理對象
放到二級緩存的意義:如果A是一個被aop代理的對象, 為了保證拿到的都是同一個代理對象,第一次調用獲取三級緩存對象之后,就把它放到二級緩存。
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Names of beans that are currently in creation */
/**
* 在創建單例bean之前加入到set集合中
*/
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
源碼中的步驟
入口:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
//忽略其他代碼
}
獲取bean的過程,一級,二級,三級
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
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;
}
Spring 不能解決哪種循環依賴
構造器依賴
// PrototypeA 構造器 B
public PrototypeA(PrototypeB b) {
this.b = b;
}
// PrototypeB 構造器 需要A
public PrototypeB(PrototypeA a) {
this.a = a;
}
報錯:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'prototypeB' defined in class path resource [beans.xml]:
Cannot resolve reference to bean 'prototypeA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeA': Requested bean is currently in creation: Is there an unresolvable circular reference?
原型類型的依賴
public class PrototypeA {
private PrototypeB b;//A->B
public PrototypeB getB() {
return b;
}
public void setB(PrototypeB b) {
this.b = b;
}
}
public class PrototypeB {
private PrototypeA a ;//B->A
public PrototypeA getA() {
return a;
}
public void setA(PrototypeA a) {
this.a = a;
}
}
x m l配置
<!-- scope都是原型prototype -->
<bean id="prototypeA" class="com.xxx.spring.demo.circularDep.PrototypeA" scope="prototype">
<property name="b" ref="prototypeB"/>
</bean>
<bean id="prototypeB" class="com.xxx.spring.demo.circularDep.PrototypeB" scope="prototype">
<property name="a" ref="prototypeA"/>
</bean>
報錯:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'prototypeB' defined in class path resource [beans.xml]:
Cannot resolve reference to bean 'prototypeA' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeA': Requested bean is currently in creation: Is there an unresolvable circular reference?