Spring是如何解决循环依赖的?
1 循环依赖
你需要我,我需要你就是循环依赖 @Component public A { @Resource private B b ; } @Component public B { @Resource private A a ; }
在Spring中使用的三级缓存来解决循环依赖问题,这里的缓存其实就是Map对象 public class DefaultSingletonBeanRegistry { // 一级缓存:完整完全初始化完成的Bean /** Cache of singleton objects: bean name to bean instance. */ private final Map singletonObjects = new ConcurrentHashMap<>(256); // 三级缓存:最终通过ObjectFactory.getObject返回对象 /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map> singletonFactories = new HashMap<>(16); // 二级缓存 /** Cache of early singleton objects: bean name to bean instance. */ private final Map earlySingletonObjects = new ConcurrentHashMap<>(16); } 1.1 获取Bean流程public abstract class AbstractBeanFactory protected T doGetBean(...) throws BeansException { // Eagerly check singleton cache for manually registered singletons. // 进入DefaultSingletonBeanRegistry类 Object sharedInstance = getSingleton(beanName); } } public class DefaultSingletonBeanRegistry { public Object getSingleton(String beanName) { return getSingleton(beanName, true); } protected Object getSingleton(String beanName, boolean allowEarlyReference) { // Quick check for existing instance without full singleton lock // 先从一级缓存中获取Bean对象 Object singletonObject = this.singletonObjects.get(beanName); // 如果不存在&当前的Bean没有被正在创建进入if块 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 从二级缓存中获取Bean对象 singletonObject = this.earlySingletonObjects.get(beanName); // 如果二级缓存中不存在&允许创建早起对象进入if块 if (singletonObject == null && allowEarlyReference) { synchronized (this.singletonObjects) { // Consistent creation of early reference within full singleton lock // DCL检查 // 从一级缓存中查找 singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 从二级缓存中查找 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) { // 从三级缓存中获取ObjectFactory对象 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); // 调用三级缓存ObjectFactory.getObject返回的对象存入二级缓存中 this.earlySingletonObjects.put(beanName, singletonObject); // 从三级缓存中删除 this.singletonFactories.remove(beanName); } } } } } } return singletonObject; } }
当获取一个Bean时会先从缓存中查找是否有相应的Bean。 1.2 依赖对象注入
1 创建A实例
2 将A实例(半初始化,属性没有填充)暴露放入缓存中 public abstract class AbstractAutowireCapableBeanFactory { protected Object doCreateBean(...) throws BeanCreationException { // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // 在这里会检查当前是否是单例Bean & 是否允许循环依赖(默认是允许的)可以通过BeanFactoryPostProcessor来改变该值setAllowCircularReferences & 当前的Bean是否正在创建中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 将当前创建出来的Bean(刚刚new出来的对象)将其放入三级缓存中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } } // 该方法的作用就是为早期创建的对象(没有进行初始化的对象)先创建代理对象。 // 前提你的开启代理功能,如:容器中创建有AbstractAutoProxyCreator类型的Bean对象(一般都是继承该类,其实就是BeanPostProcessor对象) // 开启代理(@EnableAspectJAutoProxy) 会注册AspectJAwareAdvisorAutoProxyCreator Bean进行代理对象的创建 // 简单说就是:你的提供BeanPostProcessor(一般我们都继承AbstractAutoProxyCreator类) protected Object getEarlyBeanReference(...) { 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; } } public class DefaultSingletonBeanRegistry { protected void addSingletonFactory(...) { synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } }
3 填充A实例的属性public abstract class AbstractAutowireCapableBeanFactory { Object exposedObject = bean; try { // 填充A实例属性,也就是在这里后会先再去创建依赖的B实例对象。 populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { // ... } return exposedObject ; }
4 A实例属性依赖B对象
5 创建B对象实例
6 填充B实例属性
7 B实例属性依赖A对象
8 将上面已经暴露到三级缓存中的A对象注入给B实例
在获取A对象的时候执行上面27.1中的getSingleton方法,会将三级缓存中A这个半初始化状态的对象移除,将其存入到二级缓存中。
9 B实例Bean的创建工作继续执行初始化方法public abstract class AbstractAutowireCapableBeanFactory { Object exposedObject = bean; try { // B实例将需要的A对象已经注入了(A暴露的半初始化状态对象) populateBean(beanName, mbd, instanceWrapper); // B实例Bean将继续向下执行初始化方法 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { // ... } return exposedObject ; }
B如果需要AOP代理?最终B对象是个代理对象。B到此就完全的初始化完了,B的依赖对象A此时是个半初始化状态的对象
10 B实例对象保存到一级缓存
最终B实例创建,初始化都执行完后会将自身加入到一级缓存同时清除二级,三级缓存 public abstract class AbstractBeanFactory { protected T doGetBean(...) { // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } } } // getSingleton方法 public class DefaultSingletonBeanRegistry { public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { // 从单例池中获取对象 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { beforeSingletonCreation(beanName); try { singletonObject = singletonFactory.getObject(); } catch (IllegalStateException ex) { //... } finally { afterSingletonCreation(beanName); } // 将当前创建的Bean加入单例池中,并且清除相应的二级,三级缓存 addSingleton(beanName, singletonObject); } return singletonObject; } } protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
11 A实例Bean创建继续执行
如果B是被AOP代理的那么此时的A实例注入的B对象就是一个代理对象。
12 A实例Bean执行初始化方法
13 A继续执行上面的10步骤 1.3 三级缓存解决的问题
三级缓存解决问题:循环依赖+AOP问题
只用一,二级缓存: A创建实例,将其缓存到earlySingletonObjects A填充属性,发现需要B B创建实例,将其缓存到earlySingletonObjects B填充属性,发现需要A 从earlySingletonObjects中找到A填充 B继续执行初始化方法 B创建完成 返回继续将创建的B注入到A中 A继续执行初始化方法 A,B都彼此有了对方,一切正常
从上面罗列的步骤看似乎很是完美解决了循环依赖问题,接下来我们看看加入AOP的场景
假如A,B两个对象最终都是要被AOP代理的 A创建实例,将其缓存到earlySingletonObjects A填充属性,发现需要B B创建实例,将其缓存到earlySingletonObjects B填充属性,发现需要A 从earlySingletonObjects中找到A填充(此时B中填充的对象是个原始对象) B继续执行初始化方法 B通过BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建代理对象 B创建完成,最终B是个代理的对象 返回继续将创建的B注入到A中(此时A中注入的B对象是个代理对象) A继续执行初始化方法 A通过BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建代理对象
执行到这里,A中依赖的B是代理对象没有问题,但是B中依赖的A对象是原始对象;这就不正确了应该依赖的A也必须是代理对象才是。
引入三级缓存:
三级缓存引入了ObjectFactory对象,在获取对象的时候,是调用ObjectFactory#getObject方法。
而这个getObject方法的实现实际执行的是getEarlyBeanReference方法,再来回顾下:
在创建实例时先将其存入三级缓存中: public abstract class AbstractAutowireCapableBeanFactory { protected Object doCreateBean(...) throws BeanCreationException { // 判断是否是单例 & 是否允许循环依赖 & 当前的Bean是否正在创建中 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 这里的第二个参数就是通过函数式接口实现的ObjectFactory addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } } } // 当前的Bean是否正在创建,是在哪里设置的?AbstractBeanFactory#doGetBean.getSingleton中设置的 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
getEarlyBeanReference方法就是提前创建代理对象 public abstract class AbstractAutowireCapableBeanFactory { // 在该方法中执行SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 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; } }
如果开启了AOP代理后 public abstract class AbstractAutoProxyCreator { @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // 这里在按照正常流程创建AOP代理对象时会判断缓存earlyProxyReferences中是否有(提前创建代理);防止重复创建代理对象 this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); } }
通过getEarlyBeanReference方法提前创建代理对象。这样就解决了循环依赖时AOP代理问题。保证获取的都是同一个对象。
其实引入三级缓存还解决了一个问题就是延迟代理对象的创建,如果不应用ObjectFactory方式那么我们需要不管需不需要都要先创建代理对象,而引入ObjectFactory可以在注入的时候先暴露的是ObjectFactory只有在调用getObject方法的时候才去创建真正的代理对象(避免了所有Bean都强制创建代理对象)。当没有被代理时可以直接返回原始对象,如果被代理会提前创建代理对象。
不用二级直接是用一,三级缓存?
假设场景:A 依赖 B,B 依赖 A、C,C 依赖 A
如果这样会出现不同的代理对象,每次调用getObject都会创建不同的代理对象(在上面的场景中如果只用一,三级缓存那么 B 依赖 A会通过getObject获取一个代理对象Proxy$1,接着注入C的时候 C中又依赖A,那这时候又从getObject获取对象那么返回的将又会是一个新的代理对象Proxy$2;在这个过程中A对象就出现了2个不一样的对象了,这肯定是错误的)。而引入二级缓存也就解决了这个问题。只有二级缓存没有的时候才从三级缓存汇总获取(如果需要则创建代理对象,然后保存到二级缓存中,二级缓存中已经是提前创建了代理对象(如果需要代理))。
当一个Bean完全的创建完以后放入一级缓存中,此时会吧二级三级中的缓存清除。 1.4 关闭循环依赖@Component public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { if (beanFactory instanceof AbstractAutowireCapableBeanFactory) { AbstractAutowireCapableBeanFactory bf = (AbstractAutowireCapableBeanFactory) beanFactory ; // 关闭循环依赖 bf.setAllowCircularReferences(false) ; } } }
完毕!!!!
求个关注+转发
SpringMVC参数统一验证方法
SpringBoot多数据源配置详解
SpringCloud Nacos 整合feign
Spring AOP动态代理失效的解决方法@Transactional为何会失效
SpringBoot配置文件你了解多少?
SpringBoot邮件发送示例 Springboot面试题整理附答案
SpringBoot项目查看线上日志
在Spring Cloud 中你还在使用Ribbon快来试试Load-Balancer
SpringBoot分库分表sharding-sphere3
雅诗兰黛半价,买满还能送一套,快去粉它崇光雅诗兰黛第一波优惠还在继续中如果没有想入手的宝贝,就来看看第二波优惠第二波优惠更是劲爆到哭唧唧我挑选了我最看好的选手买到真的是血赚雅诗兰黛真的不是一般豪气这次活动真的是实打实地
立冬气温骤降,老年人脑梗容易复发!记住这5点,八成可预防立冬如期而至,朋友圈被各种雪景霸屏了,接下来一场大的寒潮将席卷大江南北,气温骤降是各地即将发生的大概率事件。气象部门也预测,今年的冬天可能要比往年更加寒冷。而每年冬天,医院的神经内
钱包被掏空!海南免税ChloeLOEWE新款包包最新报价来了绝了!前有香奈儿包包涨价,没想到YSL部分包包也悄咪咪涨价了!平均差不多涨价500800元左右,这其他奢侈品还会远吗?此时,阿宝只想到一句话买包也要趁早啊啊啊!所以有海南旅游计划的
祖玛珑香水排行榜TOP10,你的上榜了吗?都说闻香识女人,简单来说,不过就是在记住一个人之前,嗅觉总是先行一步记住她的气味。若要提名一个闻上去就很贵气的香水,祖玛珑必须榜上有名。不仅是许多集美们入坑香水的首选,更是深受各路
肌肤之钥热销排行TOP8,你肯定也买过来源公众号游惠宝全球优惠众所周知,CPB的产品都不便宜,但也是真心很好用!负面评价几乎为零今天阿宝就要给仙女们介绍,8款肌肤之钥的热销护肤精品,排行是根据cdf免税店的销量情况得出
去海南免税店购物必看攻略!不看血亏最近,身边好多人趁着暑假,都去海南血拼了想必很多小可爱也在计划海南之旅,所以阿宝给大家整理了去海南免税店必看攻略!!满满都是干货,一定要耐心都看完噢!错过任何一个都是血亏Vol。1
听说,90的人都用过这10支口红早前,林更新在节目上说口红这么便宜?就两三百块?那为什么要说女生败家,这不是随便买。这段发言简直说到女生的心坎里,今天就来谈一谈怎么实现口红自由。我们以前买口红总喜欢去品牌专柜买,
男女香水榜单TOP5,你最爱的香水上榜了吗?讲真,香水真的非常特殊,每个人的嗅觉体验都不一样,所以很难靠文字就能种草。不过最近阿宝淘了两瓶,顺便扒了下cdf免税店买得最火的男女生香水,不如借此来看看大家都爱用什么,看看你最爱
精华排名榜来了!你的在哪个榜?今天是篇精华的排名榜排名是综合整理各网友使用情况得出,以下只是部分精华排名如果你有使用非常好的精华欢迎在留言区分享马上一起来康康,你的精华到底在哪个榜?01。高级榜海蓝之谜精华适合
眼霜排名榜来了!你的上哪个榜?内附眼霜挑选方法来源公众号游惠宝全球优惠今天是篇眼霜排名榜排名是综合整理各网友使用情况得出,如果你有不一样的看法,欢迎留言跟大家分享下面一起来看看你的眼霜是在哪个排名榜?宝藏榜雅诗兰黛眼霜适合所有
洗面奶评分排行榜来了!你的得多少分?今天是篇洗面奶评分排行榜评分是综合各网友使用情况得出,如果你有不一样的看法,欢迎留言分享马上一起来看看你的洗面奶可以打多少分呢?01。90分洗面奶专区尤也氨基酸洗面奶功效深层清洁参