首页 > 其他分享 >Spring三级缓存与循环依赖

Spring三级缓存与循环依赖

时间:2023-06-25 19:12:35浏览次数:32  
标签:缓存 多例 Spring bean 实例 单例 创建 三级

三级缓存

//一级缓存,存放的是完整的bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二级缓存,存放的是半成品的bean,未完成属性注入
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三级缓存,存放的是bean工厂,用来生成bean。
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环依赖

image

如何解决循环依赖

通过三级缓存可以很好的解决循环依赖:
1,A创建过程中需要B,于是A将自己放到三级缓里面,去实例化B
2,B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
3,B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。

为什么构造器注入无法解决循环依赖问题

  • 这是因为当一个类在构造函数中需要依赖另一个类的实例时,它必须等待另一个类的实例完成构造才能完成自己的构造。但是,由于另一个类也依赖于当前类的实例,它也需要等待当前类的实例完成构造。这就形成了一个相互等待的死循环,导致无法完成依赖注入。

当一个单例内部属性是多例bean时,也无法解决循环依赖

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class A {
    @Autowired
    private B b;
}

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class B {
    @Autowired
    private A a;
}

结果:

不报错。需要注意的是本例中启动时是不会报错的(因为非单例Bean默认不会初始化,而是使用时才会初始化),所以很简单咱们只需要手动getBean()或者在一个单例Bean内@Autowired一下它即可

但是:

// 在单例Bean内注入
    @Autowired
    private A a;

报错:
当单例 bean 和多例 bean 相互之间存在循环依赖时,容器在创建对象时会遇到两个主要问题:

  1. 单例 bean 的创建过程中需要引用一个还未创建的多例 bean 实例。由于多例 bean 的创建是延迟到每次请求时才进行的,所以容器无法提供未创建的多例 bean 实例。
  2. 多例 bean 的创建过程中需要引用一个还未创建的单例 bean 实例。单例 bean 在容器初始化时被创建,但它的依赖可能包含一个还未创建的多例 bean 实例,因此容器也无法提供未创建的多例 bean 实例。

标签:缓存,多例,Spring,bean,实例,单例,创建,三级
From: https://www.cnblogs.com/yliunyue/p/17503531.html

相关文章

  • spring初学
    spring是一个轻量级的java开发框架,基础是springframework,依靠springframework可以发展出很多适用于不同场合的模式  ......
  • springboot加切面日志
    packageorg.rest.util;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionP......
  • 记录--强制缓存这么暴力,为什么不使用协商缓存
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助前段时间在看面经的时候,发现很多份面经中都被问到了强缓存和协商缓存。因此我觉得有必要写一篇文章来好好聊聊这两者。强缓存和协商缓存浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问......
  • 利用SpringBoot和javafx进行桌面开发
    原文合集地址如下,有需要的朋友可以关注本文地址合集地址众所周知,SpringBoot是一款强大的Javaweb开发程序,这得益于其构造了一个Spring容器,然后通过依赖注入和控制反转,维护起一套Java对象和实例的管理机制,方便开发者去使用。在web应用开发的应用中,Springboot在Java层应用非常广,同样的......
  • 事务超时异常:org.springframework.transaction.TransactionTimedOutException: Transa
    报错如下:代码如下:Controllerimportcom.zwh.service.impl.TimeOutService;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.w......
  • 利用SpringBoot和javafx进行桌面开发
    原文合集地址如下,有需要的朋友可以关注本文地址合集地址众所周知,SpringBoot是一款强大的Javaweb开发程序,这得益于其构造了一个Spring容器,然后通过依赖注入和控制反转,维护起一套Java对象和实例的管理机制,方便开发者去使用。在web应用开发的应用中,Springboot在Java层应用非常广,......
  • SpringBoot用@Async实现异步调用
    @Async的使用1、在启动类中加上注解@EnableAsync启用异步 2、在使用异步的方法上加上注解@Async,自己写一个线程池,指定线程池。不建议使用默认的线程池。 在线程池应用中,参考阿里巴巴java开发规范:线程池不允许使用Executors去创建,不允许使用系统默认的线程池,推荐通过T......
  • springboot~stateless4j实现状态机
    状态机,包括了状态和动作,某个状态下,只能执行某些动作,如果动作不匹配,状态是不会进行变更了,这样就保护了我们状态字段的准备性,不能随意改变,必须按着我们设计的规则进行状态的轮转。Stateless实现的状态机Stateless:Stateless是一个简单且易于使用的状态机库,它提供了基本的状态转换......
  • RHEL CentOS Debian Ubuntu 如何刷新 DNS 缓存
    RHELCentOSDebianUbuntu如何刷新DNS缓存全文:如何刷新DNS缓存(macOS,Linux,Windows)UnixLinuxWindows如何刷新DNS缓存(macOS,FreeBSD,RHEL,CentOS,Debian,Ubuntu,Windows)请访问原文链接:https://sysin.org/blog/how-to-flush-dns-cache/,查看最新版。原创......
  • 如何清除浏览器的 DNS 缓存 (Chrome, Firefox, Safari)
    如何清除浏览器的DNS缓存(Chrome,Firefox,Safari)ChromeChromiumEdgeFirefoxSafariclearDNSCache,flushDNScache请访问原文链接:https://sysin.org/blog/clear-browser-dns-cache/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org天下只剩三种(主流)浏览......