一文了解Spring依赖注入时循环依赖问题

目录

什么是循环依赖

凡是Java的循环依赖都会有问题?

为什么Spring循环依赖会有问题?

Spring解决循环依赖问题的思路?

设置二级缓存对象池

方案一直接将实例化对象放入早期对象池

方案一缺点

方案二-将实例化对象处理AOP后放入早期对象池

方案二-缺点

设置三级缓存对象池

Spring解决循环依赖源码解析


什么是循环依赖

对象A依赖对象B,对象B依赖对象A,这是一种常见且正常的依赖关系。

Java原生创建对象循环依赖不会有问题

通过Java直接创建对象,并不会产生问题;因为Java创建的只需要实例化后就是一个完整的对象,循环依赖时,只需将所有的对象都先实例化,再处理依赖关系。

publc class A{public B b;
}
publc class B{public A a;
}
public class Test{public static void main(String[] args){A a = new A();B b = new B();a.b = b;b.a = a;}
}

为什么Spring循环依赖会有问题?

spring创建的bean对象,不只是简单的实例化,还要经历属性注入,初始化前,初始化,初始化后等过程,只有经历完这个过程,才是一个完整的bean。要了解spring生命周期,可以参考这篇博文:

一句话解释:处理依赖关系时,由于bean没有经历完完整的生命周期,还不是一个完整的bean,导致有循环依赖关系的bean都陷入等待对方完成状态,而无法继续向后执行。请参考下面的流程图感受下:

ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中)

Spring解决循环依赖问题的思路

设置二级缓存对象池

方案一直接将实例化对象放入早期对象池

最简单的思路就是在类似于普通对象创建的方式,在实例化后有一个原始的对象池,在判断单例池中是否有bean对象时,若无则从原始对象池中获取,可以解决上诉问题


方案一缺点

如果A的原始对象注入给B的属性之后,在初始化后阶段A的原始对象进行了AOP产生了一个代理对象,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突

方案二-将实例化对象处理AOP后放入早期对象池

放入早期对象池前,对实例化后对象A处理,若有AOP则放入代理对象A,若无AOP,则放入原始对象,如下图所示

方案二-缺点

但是在实例化后,直接处理对象A将代理对象或原始对象放入对象原始池这种方式,对所有对象的创建过程都起作用,而没有循环依赖的对象创建过程,无需将AOP过程前置,所以这个时机不合适

设置三级缓存对象池

Spring为了解决非循环依赖的对象不进行AOP前置,使采用函数式编程方式,在实例化后,先缓存一个对象工厂函数,此时不执行内部逻辑,待从原始对象池中获取对象时,才真正获取到对象工厂去调用函数获取早期对象,存放到二级缓存对象池中即早期对象池

三级缓存对象池的作用

1.单例对象池(singletonObjects中):缓存的是经历过完整生命周期后对象

2.早期对象池(earlySingletonObjects):缓存的是没有经历过完整生命周期的对象,实例化后原始对象或者实例化后的代理对象

3.对象工厂(singletonFactories):缓存的是对象工厂,对象工厂中定义了创建早期对象的函数

三者的创建时机,获取时机如下流程图:

Spring解决循环依赖源码解析

查看获取属性对象时源码也可知:获取对象时先从单例池中获取对象,获取不到从早期对象池中获取对象,若仍获取不到则从对象工厂中获取对象bean的对象工厂,创建早期对象,存入早期对象池中,并且该对象工厂从对象工厂池中删除。

@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = 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;}

对象工厂调用getObject()时,实际调用的就是

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference

会遍历所有实现了SmartInstantiationAwareBeanPostProcessor的类,调用getEarlyBeanReference获取bean

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;}

SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference会直接获取到原始bean

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {/*** Obtain a reference for early access to the specified bean,* typically for the purpose of resolving a circular reference.* <p>This callback gives post-processors a chance to expose a wrapper* early - that is, before the target bean instance is fully initialized.* The exposed object should be equivalent to the what* {@link #postProcessBeforeInitialization} / {@link #postProcessAfterInitialization}* would expose otherwise. Note that the object returned by this method will* be used as bean reference unless the post-processor returns a different* wrapper from said post-process callbacks. In other words: Those post-process* callbacks may either eventually expose the same reference or alternatively* return the raw bean instance from those subsequent callbacks (if the wrapper* for the affected bean has been built for a call to this method already,* it will be exposes as final bean reference by default).* <p>The default implementation returns the given {@code bean} as-is.* @param bean the raw bean instance* @param beanName the name of the bean* @return the object to expose as bean reference* (typically with the passed-in bean instance as default)* @throws org.springframework.beans.BeansException in case of errors*/default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {return bean;}}

但是spring提供了AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor,重写了getEarlyBeanReference方法,若开启了代理,那会直接执行AbstractAutoProxyCreator的getEarlyBeanReference获取代理后的对象

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupportimplements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware{
// 提前进行AOP@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey = getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/154976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

入行IC | 从小白助理级,到总监专家级,到底要经历怎样的成长阶段呢?

《中国集成电路产业人才发展报告》是业内和IC设计、IC人才都息息相关的一份报告。 &#xff08;文末可领全部报告资料&#xff09; * 从报告数据来看&#xff0c;无论在半导体产业的哪个环节&#xff0c;个人发展路径和年薪待遇都是逐级攀升的趋势。 那么从小白助理级&a…

口袋参谋:找关键词的三种方法!

​如何找热搜关键词&#xff1f;99%的商家都不知道。那么今天可以根据我说的三种方法去做。 第一种方法&#xff1a;利用竞争对手 通过分析竞争对手&#xff0c;正在使用和采取何种优化方法&#xff0c;来帮助你理解市场上正在流行什么样的关键字&#xff0c;这些热词可以直接从…

Java自动化驱动浏览器搜索稻香

下载最新的Chrome浏览器 查看chrome版本&#xff0c;在浏览器地址栏输入&#xff1a;chrome://version/ 下载对应的浏览器驱动&#xff0c;将其放到一个目录中&#xff0c;我放到了D:/chromedriver-win64 导入对应的依赖【注意&#xff1a;不要导入最新的版本&#xff0c;最…

数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大重点分析

数字化时代银行网点厅堂营销存在以下5大重点&#xff1a; 1、厅堂宣传。应以主推产品作为厅堂宣传的宣传重点&#xff0c;结合视频宣传、平面物料、互动机具、陈列物料等多维度&#xff0c;开展有序重复展示&#xff0c;进而加大吸引客户关注度。 2、产品推荐。在识别出中高端…

纽扣电池/含纽扣电池产品上架亚马逊各国法规标准要求16 CFR 第 1700.15/20 ANSI C18.3M(瑞西法案认证)

亚马逊纽扣电池认证标准有哪些&#xff1f; 一、美国站&#xff08;亚马逊纽扣电池/含纽扣电池商品&#xff09;安全测试标准要求&#xff1a; 16 CFR 第 1700.15 、16 CFR 第 1700.20 ANSI C18.3M、警示标签声明要求&#xff08;第 117-171 号公众法&#xff09; 二、澳大…

Linux应用开发基础知识——网络通信编程(九)

前言&#xff1a; 通过学习为后续Linux网络编程奠定基础。首先介绍网络编程的概念&#xff0c;即网络协议分层&#xff0c;旨在帮助读者对网络建立初步的、全面立体的认识&#xff0c;其次介绍包括协议、端口、地址等&#xff1b;最后介绍应用非常广泛的传输控制协议&#xff0…

CentOS8部署Skywalking(非容器方式)

一、官网下载安装包 二、安装 #tar -zxf apache-skywalking-apm-9.6.0.tar.gz #mv apache-skywalking-apm-9.6.0 skywalking #cd /opt/skywalking 修改配置文件 #vi /opt/skywalking/config/application.yml #vi vi /opt/skywalking/webapp/application.yml 三、运行 ./bin…

NLP | SimKGC论文详解及项目实现

本文主要讲解了论文SimKGC&#xff1a;基于预训练语言模型的简单对比知识图谱补全的论文总结以及项目实现。 论文题目&#xff1a;2022_SimKGC: Simple Contrastive Knowledge Graph Completion with Pre-trained Language Models 论文地址&#xff1a;2022.acl-long.295.pdf (…

竞赛 题目:基于深度学习的图像风格迁移 - [ 卷积神经网络 机器视觉 ]

文章目录 0 简介1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习卷积神经网络的花卉识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

澳洲的猫罐头怎么样呢?几款我自己亲自喂养过的优质猫罐头推荐

一款优质的猫罐头&#xff0c;必须满足三个要点&#xff1a;完整又均衡的营养配方、新鲜又优质的原料、以及科学可靠的生产工艺。 猫罐头的三个要素&#xff0c;一个都不能少。配方不均衡&#xff0c;营养就不足&#xff1b;原料不新鲜&#xff0c;生产出来的猫罐头就不优质&a…

参与活动如何进行地区的限制

对活动地区限制分为两步&#xff1a;一是管理端配置&#xff0c;而是移动端限制 移动端限制 使用高德获取经纬度&#xff08;需要引入高德库&#xff1a;https://webapi.amap.com/maps&#xff09;&#xff0c;如果是app也可以调用jsapi获取经纬度 export const checkAppPermis…

VR全景打造亮眼吸睛创意内容:三维模型、实景建模

随着VR技术在不同行业之间应用落地&#xff0c;市场规模也在快速扩大&#xff0c;VR全景这种全新的视觉体验为我们生活中的许多方面都带来了无限的可能。更加完整的呈现出一个场景或是物体的所有细节&#xff0c;让浏览者感受到自己仿佛置身于现场一般&#xff1b;其次&#xf…

WPF Button点击鼠标左键弹出菜单

目录 ContextMenu介绍WPF实现点击鼠标左键弹出菜单如何禁用右键菜单如何修改菜单样式菜单位置设置 本篇博客介绍WPF点击按钮弹出菜单&#xff0c;效果如下&#xff1a; 菜单的位置、央视可以自定义。 实现技巧&#xff1a;不在xaml里菜单&#xff0c;在按钮左键按下的点击事件里…

代码随想录二刷 | 链表 | 翻转链表

代码随想录二刷 &#xff5c; 链表 &#xff5c; 翻转链表 题目描述解题思路 & 代码实现双指针法递归法 206.翻转链表 题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4…

金蝶云星空套打设计

文章目录 金蝶云星空套打设计下载登录打开需要创建套打的单据新建套打模板数据中心-发货通知单-设置预览 金蝶云星空套打设计 下载 登录 打开需要创建套打的单据 KD开头&#xff0c;是标准产品预设。 新建套打模板 默认A4纸 默认插入三行三列。 拖入文本&#xff0c;填写内容…

Enterprise Architect安装与使用

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Enterprise Architect概述 官方网站&#xff1a;https://www.sparxsystems.cn/products/ea/&#xff1b;图示如下&#xff1a; Enterprise Architect是一个全功能的、基于…

虾皮选品免费工具:如何用知虾进行虾皮市场分析选品

在如今的电商时代&#xff0c;了解市场需求和选择热销产品是成功经营的关键。虾皮作为东南亚地区最大的电商平台之一&#xff0c;提供了一系列的选品工具&#xff0c;帮助卖家在市场竞争中脱颖而出。本文将介绍如何使用虾皮的免费工具——知虾进行虾皮市场分析选品&#xff0c;…

量子计算+物流!“最后一英里”配送难题Unisys成功实时决策

&#xff08;图片来源&#xff1a;网络&#xff09; 此前&#xff0c;供应链行业一直致力于手工操作&#xff0c;严重依赖于纸质系统。后来随着客户需求的不断变化&#xff0c;这种传统方法逐渐显出不足之处。供应链行业正在迅速转向现代化&#xff0c;采用自动化和数据驱动的…

一个快递包裹的跨国之旅

事情要从今年三月份说起&#xff0c;一位爱尔兰的同事在6月份结婚&#xff0c;团队同事准备了中国风的丝绸画轴、领带、丝巾作为礼物。3月份开始邮寄&#xff0c;4月初爱尔兰方面收件&#xff0c;5月份因为文件不足、不完整、不正确等原因被取消进口&#xff0c;7月份退回到大连…

02【SpringBoot静态处理、错误处理】

目录 一、SpringBoot的WEB开发 1.1 静态资源的处理 1.1.1 静态资源目录 1&#xff09;SpringBoot静态资源处理 2&#xff09;关于静态资源处理的配置 3&#xff09;欢迎页面的处理 4&#xff09;修改SpringBoot资源访问路径 1.1.2 WebJars资源 1.2 注册Servlet三大组件…