三级缓存:
singletonObjects:单例池,已经进过完整生命周期。
earlySingletonObjects:早期的单例池,生命周期不完整。
singletonFactories:出现循环依赖后,他去存放如何创建earlySingletonObjects的具体实现。
什么是循环依赖
A对象依赖了B对象,B对象依赖了A对象。
在Spring中,一个对象并不是简单new出来了,而是会经过一系列的Bean的生命周期(核心是属性方法的依赖注入),导致在创建Bean的过程中,出现了互相等待的情况。
ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中):这时候就会导致A和B都创建不出来。
最简单的解决循环依赖的方式:@Lazy注解,直接生成空的代理对象赋值!
俩个互相依赖的Bean都是原形的,循环依赖无法解决!因为原形的不能用之前创建的对象(每次都是一个新对象)!
构造方法的方式去循环依赖,因为无法将构造方法实例化,所以循环依赖无法解决!
解决循环依赖的思路:打破循环,让一个对象创建出来
简单理解spring是如何解决循环依赖的:三级缓存
singletonObjects:单例池,已经进过完整生命周期。
earlySingletonObjects:早期的单例池,生命周期不完整。
singletonFactories:出现循环依赖后,他去存放如何创建earlySingletonObjects的具体实现。
深入理解spring是如何解决循环依赖的:三级缓存
singletonObjects :缓存的是已经经历了完整生命周期的bean对象。
earlySingletonObjects :缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整生命周期的bean。
singletonFactories :缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
一级缓存singletonObjects源码分析
protected <T> T doGetBean (
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
.......
Object sharedInstance = getSingleton(beanName);
......
}
二级缓存earlySingletonObjects源码分析
protected Object getEarlyBeanReference (String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
public Object getEarlyBeanReference (Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this .earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
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;
}
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;
}
三级缓存singletonFactories源码分析
protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
boolean earlySingletonExposure = (mbd.isSingleton() && this .allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references" );
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
......
}
protected void addSingletonFactory (String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null" );
synchronized (this .singletonObjects) {
if (!this .singletonObjects.containsKey(beanName)) {
this .singletonFactories.put(beanName, singletonFactory);
this .earlySingletonObjects.remove(beanName);
this .registeredSingletons.add(beanName);
}
}
}
解决循环依赖最核心的代码:一二级缓存找不到会去执行三级缓存的lambda表达式,并放入二级缓存!
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this .singletonObjects.get (beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this .earlySingletonObjects.get (beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this .singletonObjects) {
singletonObject = this .singletonObjects.get (beanName);
if (singletonObject == null ) {
singletonObject = this .earlySingletonObjects.get (beanName);
if (singletonObject == null ) {
ObjectFactory<?> singletonFactory = this .singletonFactories.get (beanName);
if (singletonFactory != null ) {
singletonObject = singletonFactory.getObject();
this .earlySingletonObjects.put(beanName, singletonObject);
this .singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
进行过循环依赖,实际初始化后(AOP)拿到的值是平台对象,需要从二级缓存中获取代理对象
protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
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." );
}
}
}
}
......
}
结束语
获取更多本文的前置知识文章,以及新的有价值的文章,让我们一起成为架构师!
关注公众号,可以让你对MySQL、并发编程、spring源码有深入的了解!
关注公众号,后续持续高效的学习JVM!
这个公众号,无广告!!!每日更新!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码