Spring三级缓存

目录

循环依赖问题

三级缓存

三级缓存创建Bean的流程(解决循环依赖问题)

三级缓存的局限性


Spring的三级缓存是为了解决单例Bean的循环依赖问题而存在的。

循环依赖问题

简单来说就是A依赖B,而B又依赖A。即创建A的时候,需要先创建B;但是创建B的时候,需要先创建A。这样就陷入了死循环,两个都创建不了。

三级缓存

  • 一级缓存:存储已经完全初始化的单例Bean
  • 二级缓存:存储已经实例化但还未初始化的Bean
  • 三级缓存:存储用于创建Bean的工厂

要理解三级缓存创建Bean的逻辑,首先需要了解Bean的生命周期

  • 实例化(分配内存空间)
  • 填充属性值(解析依赖关系,注入默认属性等)
  • 初始化(设置属性值,执行逻辑等)
    1. 各种Aware通知,如BeanNameAware、BeanFactoryAware等
    2. 执行初始化前置方法
    3. 执行@PostConstruct初始化方法
    4. 执行初始化后置方法
  • 使用Bean
  • 销毁Bean

(当然在实例化之前,还要进行一些实例化前置处理,这里不讨论。)

注意:初始化一定是在填充属性值的后面,否则可能出现异常(如空指针)

三级缓存创建Bean的流程(解决循环依赖问题)

  1. 创建Bean对象时,首先看一级缓存中是否存在,如果存在,直接使用即可;
  2. 不存在则实例化一个Bean,并通过三级缓存的工厂进行填充属性和初始化。
  3. 如果这个过程存在循环依赖问题,如A需要注入B,Spring就在三级缓存中实例化B,并把B放到二级缓存中;
  4. A完成初始化后,创建成功,B也可以在二级缓存中完成初始化,并放到一级缓存中。

三级缓存的局限性

三级缓存仅用来解决单例Bean的循环依赖问题。例如原型Bean的循环依赖就无法通过三级缓存来解决。

如果原型Bean也采用三级缓存的方式,会增加巨大的开销,因为原型Bean的数量是远远多于单例Bean的,而且每个Bean的属性和状态都可能有巨大的不同,要存储这些所有的Bean和对应的工厂,耗费的资源是十分巨大的。虽然可以在一级缓存中移除已经取走的Bean,但是一级缓存是通过一个ConcurrentHashMap来维护的,频繁的进行移除操作,对性能影响也很大。再者从设计理念上来说,原型Bean是每次创建都获取到一个新的对象,从缓存中取显然不满足这个理念。因此原型Bean的循环依赖问题不适合用三级缓存来解决。事实上,创建原型Bean的时候,如果存在循环依赖的问题,Spring会直接抛异常。

因此在设计上,应该避免使用循环依赖。

相关推荐
Patrick在香港2 小时前
Python Docker镜像从1.2GB到89MB:多阶段构建的完整优化实录
java·python·docker·信息可视化·容器·数据分析·ai编程
上海安当技术3 小时前
敏感数据怎么防拖库?信封加密(DEK+KEK 二层密钥)架构设计与 Java 实战
java·开发语言·python
我是唐青枫3 小时前
Java JCommander 实战详解:用注解解析命令行参数
java·开发语言
大鹏说大话3 小时前
C++ 内存布局详解:类、虚函数、虚表底层原理
java·开发语言
还是鼠鼠3 小时前
Spring AI连接DeepSeek与通义千问:application.yaml配置详解
java·通义千问·spring ai·deepseek
無a伟4 小时前
redis缓存完整详解
数据库·redis·缓存
计算机小白一个4 小时前
蓝桥杯 Java B 组之哈希表应用(两数之和、重复元素判断)
java·数据结构·算法·蓝桥杯
sunburn-5 小时前
Java 队列全面详解:从入门到面试实战
java·开发语言·汇编·ide·idea
vx-程序开发6 小时前
springboot农产品运输服务平台---附源码75498
java·javascript·spring boot·python·eclipse·django·php
攻城有术6 小时前
专项攻克——spring、springMVC、springBoot、springCloud的启动流程
spring boot·spring·spring cloud