Spring三级缓存解决循环依赖
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?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现