iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Spring解决循环依赖的方法(三级缓存)
  • 403
分享到

Spring解决循环依赖的方法(三级缓存)

2024-04-02 19:04:59 403人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

  说起spring,作为流水线上装配工的小码农,可能是我们最熟悉不过的一种技术框架。但是对于Spring到底是个什么东西,我猜作为大多数的你可能跟我一样,只知道ioc、DI,却并不

  说起spring,作为流水线上装配工的小码农,可能是我们最熟悉不过的一种技术框架。但是对于Spring到底是个什么东西,我猜作为大多数的你可能跟我一样,只知道ioc、DI,却并不明白这其中的原理究竟是怎样的。在这儿你可能想得完整的关于Spring相关的知识,但是我要告诉你对不起。这里不是教程,只能作为你窥探spring核心的窗口。我不做教程,因为网上的教程、源码解析太多,你可以自行选择学习。但我要提醒你的是,看再多的教程也不如你一次的主动去追踪源码

  好了,废话说了这么多就是提醒你这里不是一个教程。只是一个描绘似的谈论,期间会有一些知识或举例缺陷,所以期望你的指正。

  今天,我们要说的是spring是如何解决循环依赖的。对于一个问题说解决之前,我们首先要先明确形成问题的本因。那么循环依赖,何为循环依赖呢?

  这里我们先借用一张图来通过视觉感受一下,看图:

  

  其实,通过上面图片我想你应该能看图说话了,所谓的循环依赖其实就是一种死循环。想象一下生活中的例子就是,你作为一个猛男喜欢一个萝莉,而萝莉却爱上了你的基友娘炮,但是娘炮心理却一直想着和你去澡堂洗澡时捡你扔的肥皂。

  是的,这就是循环依赖的本因。当spring启动在解析配置创建bean的过程中。首先在初始化A的时候发现需要引用B,然后去初始化B的时候又发现引用了C,然后又去初始化C却发现一个操蛋的结果,C引用了A。它又去初始化A一次循环无穷尽,如你们这该死的变态三角关系一样。

  既然形成了这种看起来无法 解决的三角关系,那么有什么办法解决呢?相信聪明的你在面对这样尴尬的境地,已经开始思考解决方案了。想不想的出来没关系,我们看看spring的大神们是如何来解决这个问题的。

  Spring解决循环依赖的方法就是如题所述的三级缓存、预曝光。

  Spring的三级缓存主要是singletonObjects、earlySingletonObjects、singletonFactories这三个Map:

  代码 1-1:



    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

我们知道了Spring为解决循环依赖所定义的三级缓存了,那么我们就来看看它是如何通过这三级缓存来解决这个问题的。

代码 1-2:


@Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);  //首先通过beanName从一级缓存获取bean
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {  //如果一级缓存中没有,并且beanName映射的bean正在创建中
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);  //从二级缓存中获取
                if (singletonObject == null && allowEarlyReference) {  //二级缓存也没有
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);  //从三级缓存获取
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();  //获取到bean
                        this.earlySingletonObjects.put(beanName, singletonObject);  //将获取的bean提升至二级缓存
                        this.singletonFactories.remove(beanName);  //从三级缓存删除
                    }
                }
            }
        }
        return singletonObject;
    }

上面的方法就是Spring获取single bean的过程,其中的一些方法的解释我就直接借用其它博主的文摘了:

  • isSingletonCurrentlyInCreation():判断当前 singleton bean 是否处于创建中。bean 处于创建中也就是说 bean 在初始化但是没有完成初始化,有一个这样的过程其实和 Spring 解决 bean 循环依赖的理念相辅相成,因为 Spring 解决 singleton bean 的核心就在于提前曝光 bean。
  • allowEarlyReference:从字面意思上面理解就是允许提前拿到引用。其实真正的意思是是否允许从 singletonFactories 缓存中通过getObject()拿到对象,为什么会有这样一个字段呢?原因就在于 singletonFactories 才是 Spring 解决 singleton bean 的诀窍所在。

好了,说道这里我们来缕清一下当我们执行下面代码获取一个name为 user 的bean时Spring都经过了怎样的过程。

代码 1-3:


ClassPathResource resource = new ClassPathResource("bean.xml");
 DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
 reader.loadBeanDefinitions(resource);
 UserBean user = (UserBean) factory.getBean("user");

通过追踪源码我们发现getBean()方法执行后会调用到AbstractBeanFactory.doGetBean()方法,在此方法中调用了我们上文提到的关键getSingleton()。因为开始启动项目,获取第一个bean时缓存都是空的,所以直接返回一个null。追踪源码发现,在doGetBean()后面会调用到AbstractAutowireCapableBeanFactory.doCreateBean()方法进行bean创建,详细流程就自行追踪源码。在这个方法中有一段代码:

代码 1-4:


// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName)); //通过条件判断该bean是否允许提前曝露
   if (earlySingletonExposure) {
      if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
     }
     addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); //允许提前暴露的bean 添加到三级缓存
}

通过上面的代码我们发现,可以提前暴露的bean通过addSingletonFactory()方法添加到了三级缓存SingletonFactories 中,我们看一下它是怎样操作的。

代码 1-5:


protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);  //添加到三级缓存
                this.earlySingletonObjects.remove(beanName);
                this.reGISteredSingletons.add(beanName);
            }
        }
    }

此时,我们的user这个bean就被加入到了三级缓存中,那么什么样bean的才会被加入到三级缓存中呢?就是代码 1-4中的三个判断条件:

  • 单例
  • 允许循环引用的bean
  • 当前 bean 正在创建中

到这里user这个bean已经创建,但是它还不是一个完整的bean,还需要后续的初始化。但是这不影响其它的bean引用它,假设user为开始图中的A,那么当在初始化A(user)的时候,发现A中有一个属性B,在调用方法applyPropertyValues()去设置这个B的时候。会发现B还没创建,Spring就会在重复创建A的流程调用doCreate()来创建B,然后添加到三级缓存,设置B的属性C时,发现C也还没创建,接着重复前述doCreate()步骤进行C的创建。C创建完成,进行初始化发现C引用了A,这时关键的地方就是上面的代码1-2处。

在C设置属性A的时候,调用getSingleton()获取bean时,因为A已经在代码1-4处添加到了三级缓存中,C可以直接获取到A的实例并设置成功后,继续完成自己创建。初始化完成后,调用如下方法将自己添加到一级缓存。

代码 1-6:


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

至此,Spring对于循环依赖的解决就说完了。总结来看,就想你们三角关系中那样,娘炮在缠着你捡肥皂的时候,你可以先把肥皂扔到地上安抚一下他。然后,再去追求你要的萝莉。然而他也可能做出一个假象安抚萝莉,而萝莉也可能把你加入云胎库。最后的结果要等真正使用时才知道……

到此这篇关于Spring解决循环依赖的的方法(三级缓存)的文章就介绍到这了,更多相关Spring循环依赖内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring解决循环依赖的方法(三级缓存)

本文链接: https://www.lsjlt.com/news/157480.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring解决循环依赖的方法(三级缓存)
      说起Spring,作为流水线上装配工的小码农,可能是我们最熟悉不过的一种技术框架。但是对于Spring到底是个什么东西,我猜作为大多数的你可能跟我一样,只知道IOC、DI,却并不...
    99+
    2024-04-02
  • Spring三级缓存解决循环依赖
    目录一级缓存为什么不能在实例化A之后就放入Map?二级缓存 二级缓存已然解决了循环依赖问题,为什么还需要三级缓存?三级缓存 源码 我们都知道Spring中的BeanFactory是一...
    99+
    2024-04-02
  • Spring三级缓存解决循环依赖的过程分析
    目录循环依赖解决思路解决流程二个缓存不行?总结循环依赖 什么是循环依赖?很简单,看下方的代码就知晓了 @Service public class A { @Autowired...
    99+
    2023-05-14
    Spring循环依赖 Spring三级缓存解决循环依赖
  • Spring使用三级缓存解决循环依赖的问题
    Spring如何使用三级缓存解决循环依赖在没开始文章之前首先来了解一下什么是循环依赖 @Component public class A { @Autowired ...
    99+
    2024-04-02
  • Spring为什么需要三级缓存解决循环依赖
    今天小编给大家分享一下Spring为什么需要三级缓存解决循环依赖的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。bean生命周...
    99+
    2023-06-29
  • Spring解决循环依赖问题及三级缓存的作用
    目录前言1什么是循环依赖2 如何解决循环依赖3无法解决的循环依赖前言 所谓的三级缓存只是三个可以当作是全局变量的Map,Spring的源码中大量使用了这种先将数据放入容器中等使用结束...
    99+
    2024-04-02
  • Spring为何需要三级缓存解决循环依赖详解
    目录前言bean生命周期三级缓存解决循环依赖总结前言 在使用spring框架的日常开发中,bean之间的循环依赖太频繁了,spring已经帮我们去解决循环依赖问题,对我们开发者来说是...
    99+
    2024-04-02
  • 教你Spring如何使用三级缓存解决循环依赖
    一级缓存存放实例化对象 。二级缓存存放已经在内存空间创建好但是还没有给属性赋值的对象。三级缓存存放对象工厂,用来创建提前暴露到bean的对象。 @Service public cla...
    99+
    2024-04-02
  • 怎么使用Spring三级缓存解决循环依赖问题
    这篇文章主要介绍了怎么使用Spring三级缓存解决循环依赖问题的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Spring三级缓存解决循环依赖问题文章都会有所收获,下面我们一起来看看吧。循环依赖什么是循环...
    99+
    2023-07-05
  • Spring源码之循环依赖之三级缓存详解
    目录循环依赖定义三种循环依赖的情况1.构造器循环依赖2.settler循环依赖3.prototype范围的依赖处理三级缓存机制整体分析源码分析面试题总结循环依赖 定义 循环依赖就 循...
    99+
    2024-04-02
  • 你知道怎么用Spring的三级缓存解决循环依赖吗
    目录1. 前言2. Spring Bean的循环依赖3. Spring中三大循环依赖场景演示3.1 构造器注入循环依赖3.2 singleton模式field属性注入循环依...
    99+
    2024-04-02
  • Spring解决循环依赖问题及三级缓存的作用是什么
    本文小编为大家详细介绍“Spring解决循环依赖问题及三级缓存的作用是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring解决循环依赖问题及三级缓存的作用是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-07-02
  • 关于Java Spring三级缓存和循环依赖的深入理解
    目录一、什么是循环依赖?什么是三级缓存?二、三级缓存如何解决循环依赖?三、使用二级缓存能不能解决循环依赖?一、什么是循环依赖?什么是三级缓存? 【什么是循环依赖】什么是循环依赖很好理...
    99+
    2024-04-02
  • Spring循环依赖的解决方法
    这篇文章主要介绍Spring循环依赖的解决方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!循环依赖其实就是循环引用,很多地方都说需要两个或则两个以上的bean互相持有对方最终形成闭环才是循环依赖,比如A依赖于B,B...
    99+
    2023-06-06
  • 一篇文章带你理解Java Spring三级缓存和循环依赖
    目录一、什么是循环依赖?什么是三级缓存二、三级缓存如何解决循环依赖?三、使用二级缓存能不能解决循环依赖?总结一、什么是循环依赖?什么是三级缓存 【什么是循环依赖】什么是循环依赖很好理...
    99+
    2024-04-02
  • 浅谈Spring解决循环依赖的三种方式
    引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错。下面说一下Spring是如果解决循环依赖的。第一种:构造器参数循环依赖表示通过构造器注入构成的...
    99+
    2023-05-30
    spring 循环 依赖
  • spring循环依赖解决的方法是什么
    Spring循环依赖是指两个或多个Bean之间存在相互依赖的情况。在Spring容器启动时,如果存在循环依赖,会抛出BeanCurr...
    99+
    2023-09-27
    spring
  • Spring循环依赖的解决方案详解
    目录简介方案1. Feild注入单例(@AutoWired)方案2. 构造器注入+@Lazy方案3. Setter/Field注入单例方案4. @PostConstruct方案5. ...
    99+
    2024-04-02
  • Spring轻松解决循环依赖
    目录解决循环依赖的原理源码解析总结Spring 框架是一个流行的Java应用程序框架,它提供了许多强大的功能,如依赖注入和面向切面编程。然而在使用 Spring 框架时,我们可能会遇...
    99+
    2023-05-16
    Spring循环依赖怎么解决 Spring循环依赖
  • Spring怎么解决循环依赖
    本篇内容介绍了“Spring怎么解决循环依赖”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!写在前面最近,在...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作