范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

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

路由器WiFi网速慢,多半是旁边放了这3样东西,难怪变卡顿路由器的旁边放置了一下这三种物品,会导致网速变得又慢又卡,好多人居然还不知道。赶紧跟着我一起来了解一下吧。一金属物品首先先来了解一下路由器的工作原理,路由器所发射的信号本质上就是电09年1200万像素的尼康d3s,实战效果前几天淘了个尼康家的老旗舰方块机到了,今天终于有机会出去试拍了。不多废话直接上图!买之前,最让人担心的就是那1200万像素不够用。事实上,只要认真构图,或者稍微裁一点,还好。裁多了我们的宇宙,存在时间倒流的反宇宙吗?宇宙中,所有事物都需要遵循三个对称中的任意一个C对称,电荷对称P对称,宇称对称(镜像对称)T对称,时间对称。宇宙对称性,一直被认为是宇宙的公理,但是随着物理学的发展,科学家发现每一涨价有底气!iPhone14Pro的三大卖点,干掉用了5年的刘海只是其一在华为因众所周知的原因成为统计数据中的others手机品牌后,苹果在高端市场是一家独大。5个多月后,新款iPhone14系列就将如约而至。作为大改款,旗舰iPhone14Pro系列谁是公认的拍照王者?盘点三大顶尖影像旗舰,iPhone都要靠边站2022第一季度已经结束,各大品牌也相继推出了自己的当家旗舰,其中影像系统作为旗舰机装备竞赛的重点考察项目,更是从硬件到算法调教都带来了众多升级体验,旨在和友商拉开差距。那么在20新款比亚迪唐EV首发亮相,最大续航超700km,卖30万贵么?4月1日,新款比亚迪唐EV正式首发,相比老款车外观配置及续航进行多方面的升级,它将在4月中下旬预售,5月中旬上市,售价区间可能在3035万元。首先来看外观颜值方面,2022款比亚迪连开五场发布会,vivo急了文宁雯vivo又双叒叕开发布会了。2022年5月19日晚,vivo发布了S15系列。如果说S系列更新本在情理之中的话,那么上个月,vivo的发布会属实有点多。4月11日25日,vi国产特斯拉Model3入手5个月,总结6点用车感受,3大缺点才是痛点特斯拉Model3入手5个月,总结了6点用车感受,真心后悔了,早知道就入手比亚迪汉EV或者小鹏P7,虽然特斯拉优势明显,但几大劣势才是痛点,个个扎心,选择纯电动汽车一定要三思,多方真的只有中国人喜欢给手机贴膜戴手机壳吗?大家好,我在德语系国家生活十来年,自从智能手机风靡,iPhone4到现在的华为,三星,iPhone这些手机统治市场,身边的很多人也会都在跟着时代的节奏。也有人用着非常老的手机,我国华硕RTX206012GB显卡价格曝光约合3578元英伟达RTX206012GB显卡已经正式发布,多家厂商同时推出了自家的新产品。这款显卡没有公版设计,因此也没有英伟达官方指导价。据外媒tomshardware报道,华硕的两款Dua罗永浩将进军AR和VR领域新酷产品是第一个免费尝试的产品,许多优质专家分享独特的生活经验。锤子科技CEO罗永浩曾在计划中表示,还款速度比预期的要快得多。罗永浩将再次涉足高科技领域!今天凌晨,罗永浩与网民互动
雅诗兰黛半价,买满还能送一套,快去粉它崇光雅诗兰黛第一波优惠还在继续中如果没有想入手的宝贝,就来看看第二波优惠第二波优惠更是劲爆到哭唧唧我挑选了我最看好的选手买到真的是血赚雅诗兰黛真的不是一般豪气这次活动真的是实打实地立冬气温骤降,老年人脑梗容易复发!记住这5点,八成可预防立冬如期而至,朋友圈被各种雪景霸屏了,接下来一场大的寒潮将席卷大江南北,气温骤降是各地即将发生的大概率事件。气象部门也预测,今年的冬天可能要比往年更加寒冷。而每年冬天,医院的神经内钱包被掏空!海南免税ChloeLOEWE新款包包最新报价来了绝了!前有香奈儿包包涨价,没想到YSL部分包包也悄咪咪涨价了!平均差不多涨价500800元左右,这其他奢侈品还会远吗?此时,阿宝只想到一句话买包也要趁早啊啊啊!所以有海南旅游计划的祖玛珑香水排行榜TOP10,你的上榜了吗?都说闻香识女人,简单来说,不过就是在记住一个人之前,嗅觉总是先行一步记住她的气味。若要提名一个闻上去就很贵气的香水,祖玛珑必须榜上有名。不仅是许多集美们入坑香水的首选,更是深受各路肌肤之钥热销排行TOP8,你肯定也买过来源公众号游惠宝全球优惠众所周知,CPB的产品都不便宜,但也是真心很好用!负面评价几乎为零今天阿宝就要给仙女们介绍,8款肌肤之钥的热销护肤精品,排行是根据cdf免税店的销量情况得出去海南免税店购物必看攻略!不看血亏最近,身边好多人趁着暑假,都去海南血拼了想必很多小可爱也在计划海南之旅,所以阿宝给大家整理了去海南免税店必看攻略!!满满都是干货,一定要耐心都看完噢!错过任何一个都是血亏Vol。1听说,90的人都用过这10支口红早前,林更新在节目上说口红这么便宜?就两三百块?那为什么要说女生败家,这不是随便买。这段发言简直说到女生的心坎里,今天就来谈一谈怎么实现口红自由。我们以前买口红总喜欢去品牌专柜买,男女香水榜单TOP5,你最爱的香水上榜了吗?讲真,香水真的非常特殊,每个人的嗅觉体验都不一样,所以很难靠文字就能种草。不过最近阿宝淘了两瓶,顺便扒了下cdf免税店买得最火的男女生香水,不如借此来看看大家都爱用什么,看看你最爱精华排名榜来了!你的在哪个榜?今天是篇精华的排名榜排名是综合整理各网友使用情况得出,以下只是部分精华排名如果你有使用非常好的精华欢迎在留言区分享马上一起来康康,你的精华到底在哪个榜?01。高级榜海蓝之谜精华适合眼霜排名榜来了!你的上哪个榜?内附眼霜挑选方法来源公众号游惠宝全球优惠今天是篇眼霜排名榜排名是综合整理各网友使用情况得出,如果你有不一样的看法,欢迎留言跟大家分享下面一起来看看你的眼霜是在哪个排名榜?宝藏榜雅诗兰黛眼霜适合所有洗面奶评分排行榜来了!你的得多少分?今天是篇洗面奶评分排行榜评分是综合各网友使用情况得出,如果你有不一样的看法,欢迎留言分享马上一起来看看你的洗面奶可以打多少分呢?01。90分洗面奶专区尤也氨基酸洗面奶功效深层清洁参