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

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

小米回应印度扣压48亿有一个词叫莫须有,这不是针对个人或者某家公司的掠夺,而是不同意识形态的国家间没有硝烟的战争。对印度我从来就没有好映象,这样一个迷之自信的国家,我对待这样国家的客户,30的定金,交货一招就能解决,连续开几天电脑,反应变慢的问题这电脑配置不算低吧如上图所示,这电脑配置不算低吧,但电脑连续开几天后,操作起来反应非常慢。又不愿意重启电脑。我还以为电脑配置低,但实际并非电脑配置低。经过多方面研究,终于把问题解决。com。cn。net为啥会有那么多的域名后缀?你知道它们的区别吗?经常在网上冲浪,除了直接点击链接直接打开网页外,有时候我们还会好奇在地址栏上看到很多的网址后缀。像什么。com。cn。net等等。那么这些网址后缀又有什么特别的含义吗?这次,就让我把电脑音量调高,音箱音量调低和把电脑音量调低,音箱音量调高两种情况达到同一分贝时音质有区别吗?把电脑音量调高,把音箱音量调低能够得到更好的音质在理想电路中,是没有区别的。但是在实际线路中,要考虑这个区别1如果后级音响本身信噪比不好,或连接线的屏蔽层接地不够良好,有沙沙声噪音虚惊一场!阿里一度暴跌9,胡编辑亲自澄清马某某是谁?虚惊一场!阿里一度暴跌9,胡锡进亲自澄清马某某是谁?2022年4月25日,杭州市国家安全局依法对勾结境外反华敌对势力,涉嫌从事煽动分裂国家煽动颠覆国家政权等危害国家安全活动的马某某Java中四种垃圾回收算法思想标记清除算法最基础的收集算法是标记清除(MarkSweep)算法,算法分为标记和清除两个阶段首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。它的主要缺点有两个从马某到马某某,阿里躺枪暴跌,是谁在把中概股置于死地?作者谢筱白点击名片关注今天上午一条大新闻,一字之差,直接让阿里股价崩盘近10个点。杭州,马某这样的字眼,在这个风声鹤唳又全员静默的环境中,撩动着无数静极思动投资者脆弱的神经。尽管大再登珠峰,未来几天将在珠峰开展生理适应科考研究央视新闻报道,未来几天,我国科研人员将在珠峰及周边高海拔地区开展生理适应科考研究!位于喜马拉雅山脉中部的世界最高峰珠穆朗玛峰(以下简称珠穆朗玛峰,海拔8848。13米)以其独特的自曝双处理器配置华为P60Pro,华为P50悲惨价格骤降,不买就亏了曝光6英寸小屏矩形副屏华为P60Pro旗舰级别版至于芯片问题可能会采用双处理器配置,让芯片面积增大,曝光6英寸小屏矩形副屏华为P60Pro旗舰级别版核心数量增多,从而增加手机性能。从iPhone12换到iPhone13,配置外观变化不大,但真实体验不吐不快用了一年多的iPhone12因为电池健康下滑太严重,手机续航越来越短,最终还是把它换掉了,其实在iPhone12刚买来的时候,100电池健康状态下续航也很差,不玩游戏日常使用基本也昔日断供华为,如今靠华为挽回面子,外媒高通又一次证明了华为关注我,不错过每一篇好文。有消息称,美国高通很快就要推出一款定制化的骁龙8Gen1处理器芯片,该芯片是原版骁龙8Gen1的改良版,业界普遍猜测这款芯片将专供华为。据悉,此款骁龙8G
关于特斯拉自动驾驶系统的IEEE报告的有趣之处电气和电子工程师协会(IEEE)刚刚发布了一份题为自动驾驶辅助警报中可变性的安全影响的报告。特斯拉社区中的许多人都试图理解其中一位作者的奇怪之处。这位作者担任Veoneer的独立董转载电动汽车安全吗?天马科创投姚晓菲呼吁回归车的本质自动驾驶技术,再一次被推到了风口浪尖之上。7月30日,上海浦东新区发生一起严重交通事故,一辆蔚来EC6在高速上撞击石墩后起火燃烧,驾驶员不幸遇难。不到半个月后,上善若水投资管理公司HUAWEIHILINK生态新品李文703智能锁即将发售近日李文智能锁新品指纹锁李文703智能锁,已经正式通过HUAWEIHiLink认证,作为李文锁城旗下首款通过HUAWEIHiLink认证的半自动智能锁,李文703即将正式上市与大家姚振华低调实干地布局汽车全产业链宝能集团加速造车计划从姚振华宣布跨界造车以来,宝能集团在汽车全产业链的布局便一直在不断推进,如今宝能汽车带来了越来越多的新成果,也是对其造车实力的一次次直观展示。宝能宝能集团对汽车领域业务的布局最早可支付后关注公众号下架,它的使命完成了移动支付网作者慕楚支付后关注公众号下架了。8月19日,微信支付发布公告称,为了保障用户权益,提升用户使用体验,将于2021年9月1日起下线支付后推荐关注公众号功能。在笔者看来,微信OPPOfindx3与苹果12的差距在哪里在上一篇文章中题到OPPOfindx3,与苹果12,有些网友却与我的看法产生了歧义,所以我特来写这篇文章来深究一下OPPOfindx3与苹果12的不同。处理器强劲的a14相当于872021823APPSTORE苹果IOS限时免费APP关注我每日稳定更新。所有限免APP下载均为免费,若显示收费,不要下载说明限时免费已过。再请注意的是下载的时候认准APP图标logo,不要下错了。1扫描口袋宝轻描尊享版(原价68)工高通突然为华为提供5G芯片,美国的如意算盘是如何精算的?华为最近爆出在9月中旬要发布一款新的手机,这款手机叫NOVA9系列,这个消息刚刚公布有人就问了,是5G还是4G。为什么要这样问?7月中旬华为发了一款应该说配置非常高的手机,是旗舰手为什么说HSL德国海外仓是高品质仓库随着跨境电商已经成为各国直接B2BB2C交易商品的主流模式,必定每天在卖家和消费者之间流通着大量商品,那么商品储存和物流配送就是必要的关键环节。如今全世界各地大大小小的海外仓都挤进36氪首发提供覆盖区域园区工厂的三级双碳智慧能源网络,极熵科技获数千万元A轮融资作者Ben编辑石亚琼秦明36氪获悉,双碳能源数智化平台上海极熵数据科技有限公司(以下简称极熵科技)宣布完成由真格基金投资的A轮数千万元融资。本轮募集资金将用于市场拓展和技术研发。极如何看待VIVO启动自研芯片计划?近日,有媒体报道VIVO启动自研手机芯片计划,今天我们来探讨一下。我认为可信度还是挺高的,你问我要更多的证据来支持我的观点那是没有,不过,从逻辑上能够说的通。世界主流手机厂商主要有