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
这样泡脚伤阴,不要再做了俗话说树枯根先竭,人老脚先衰。中医认为,我们的足三阴经和足三阳经分别起始和终止于脚部,它们与手三阴手三阳经共同维持着人体气血运行,是精气之根。现代医学也认为,脚对人体的血液循环起着
每天学习一味中药麦芽今天聊聊麦芽,也是很好且常用的消食药,禾本科植物大麦的成熟果实经过发芽干燥而成。麦芽在全国各地均有分布生产,将大麦洗干净,浸泡四至六小时,捞出后保持适宜的温度与湿度,等待其发芽,待
前胸后背长痘,痤疮or毛囊炎?医生给出几大防治绝招,简单好用毛囊炎是皮肤科室中最为常见的皮肤疾病之一,是由细菌真菌病毒感染或毛囊损伤为主要发病原因的化脓性炎症疾病。毛囊炎长啥样?细菌性毛囊炎初起为与毛囊口一致的红色充实性丘疹或由毛囊性脓疱疮
玻璃女神赵蕊蕊曾与姚明闹出绯闻,40岁仍未婚只因不将就18岁首次为国出战便帮助球队拿到亚锦赛冠军,出道即巅峰却长期饱受伤病困扰,退役后转型当起作家,她就是被称为玻璃美人的前女排主力副攻赵蕊蕊。赵蕊蕊出生于1981年10月,不久前刚度过
中国最大沙漠藏有地下海洋,为何不去采?有什么难言之隐?中国最大沙漠发现地下海洋,淡水远超世界20为何迟迟不去开采?你敢想象吗?中国最大的沙漠塔克拉玛干沙漠下面竟隐藏着一片地下海洋,这是一片毫无生命体征的死亡之海。这里平均降水量不足10
行星是如何形成的?一颗突然闯入太阳系的流浪太空岩石揭开谜底2017年,一块形状奇特轨道异常不稳定的岩石席卷了太阳系,它一到就离开。天文学家很快意识到它不是来自这里的。它从上到下穿过行星的轨道平面,就像向飞镖盘的同心环投掷的飞镖一样,它移动
沙漠植被基因金矿值得挖掘智利研究团队在智利北部的阿塔卡马沙漠建立了一个无与伦比的天然实验室,这里是地球上最干燥最恶劣的环境之一。图片来源美国国家科学院院刊一个国际科研小组研究了能在地球上最恶劣环境之一智利
科学家开发新技术有望制造出牢不可破的复合玻璃屏幕由于昆士兰大学进行的突破性研究,手机屏幕破裂可能成为过去的事情。由昆士兰大学的侯京伟博士王连洲教授和陈薇琪教授领导的全球研究团队,已经开发了生产下一代复合玻璃的技术,用于照明LED
撒哈拉沙漠有多深,如果挖空沙子,下面还能剩下什么?综述在我们的中学学习中,经常会出现这样一个有意思的现象,就是往往那些最特别的事物最能引起我们的兴趣,也最令我们印象深刻,比如各种世界之最。世界上最高的山峰,珠穆朗姆峰,世界上最长的
沙漠之下有很多石油,但为什么我国不愿开采?看完佩服中国的智慧综述18世纪以来,英国传统的工厂手工业逐渐无法满足广大的市场需要,珍妮纺织机被生产了出来,代表了工业革命的序章,这时机器其实并没有受到广泛的应用。直到瓦特将蒸汽机进行了改良,英国原
吉林大学发现距今约9000年的古老遗传谱系中国青年报客户端讯(中青报中青网记者王培莲)近日,由吉林大学牵头的中外研究团队发布最新研究成果借助最新的古基因组技术,研究人员发现新疆塔里木盆地的古老人群代表了一支距今约9000年