当前位置: 首页 > java >正文

彻底理解Spring三级缓存机制

文章目录

  • 前言
  • 一、Spring解决循环依赖时,为什么要使用三级缓存?


前言

  Spring解决循环依赖的手段,是通过三级缓存

  • singletonObjects:存放所有生命周期完整的单例对象。(一级缓存)
  • earlySingletonObjects:存放所有完成了实例化操作的早期单例对象。(二级缓存)
  • singletonFactories:存放单例工厂的对象,通过工厂创建早期Bean。(三级缓存)
    在这里插入图片描述
      具体Spring是如何解决循环依赖问题的,在Spring循环依赖源码分析中已经详细说明,本篇侧重于证明三级缓存的必要性。

一、Spring解决循环依赖时,为什么要使用三级缓存?

  这是一道非常经典的面试题。如果一个对象需要被代理,那首先需要生成一个普通的对象,而代理对象和普通对象是不能同时存在于容器中的,当一个对象需要使用代理的时候,就要使用代理对象覆盖掉原来的普通对象。
  这是一个典型的循环依赖场景,存在两个相互引用的 Bean:A 和 B。其中 A 包含 b 属性,B 包含 a 属性。无论是否存在循环依赖,这两个 Bean 在完成实例化后都会自动存入三级缓存。需要注意的是,通过反射创建的实例对象与放入三级缓存工厂中的对象实际上是同一个引用在这里插入图片描述
  然后A对象执行属性注入,发现需要B属性,B在容器中是不存在的,于是需要去创建B对象。
  B对象在执行属性注入,发现需要A属性,需要从容器中获取:
在这里插入图片描述
  这里从三级缓存中,可以获取到创建A对象的工厂方法,如果A对象需要AOP,则会:
在这里插入图片描述
  为B的A属性赋值时,使用的是经过AOP处理的A对象。在B完成初始化后,A对象完成属性注入并继续初始化流程,此时不会再次进行AOP处理。这意味着A对象和B对象中的A属性实际上指向同一个经过AOP处理的对象实例。这就是三级缓存存在的意义。
  如果仅使用二级缓存,给B的A属性赋值的是未经AOP处理的原始A对象。随后A继续完成后续生命周期并经过AOP处理,导致最终生成的A对象与B持有的A对象不同——前者经过AOP增强,而后者仍是原始对象


  这里可能会有一个疑惑的点,那就是,A对象和B中的A属性应该是同一个实例,如果A继续完成后续生命周期并执行AOP处理,最终将成为AOP增强对象。那么即便最初B获取A属性时,A尚未经过AOP处理,当A完成整个流程后,B中的A是否也会自动成为AOP增强对象?
  答案是否定的,因为Spring 中对 A 做 AOP 是通过“生成一个新的代理对象”,而不是修改原始 A 的引用本身:

  • B 中的 a 是早期注入进去的,它的类型是原始 A
  • Spring 后续创建了 proxyA,它是一个新对象,代理了原始 A
  • 但此时 B 中早就注入好了,不会“回头替换”那个引用
  • 所以 B 中的 A 就是原始对象,没有事务、没有切面

  一个简单案例即可证明:

public class MyService {public void doSomething() {System.out.println("Doing something...");}
}
@Aspect
public class LogAspect {@Before("execution(* MyService.*(..))")public void before() {System.out.println(">>> [AOP] Before method execution");}
}
public class AopTest {public static void main(String[] args) {MyService target = new MyService();// 创建代理工厂并添加切面AspectJProxyFactory factory = new AspectJProxyFactory(target);factory.addAspect(new LogAspect());// 获取代理对象MyService proxy = factory.getProxy();System.out.println("target = " + target.getClass());System.out.println("proxy  = " + proxy.getClass());System.out.println("是否同一引用: " + (target == proxy));proxy.doSomething();}
}

在这里插入图片描述

http://www.xdnf.cn/news/10414.html

相关文章:

  • SOD-123和SOD-123FL封装到底有什么区别?
  • Python训练营打卡 Day42
  • CS144 - Lecture 2
  • day 1 任务以及具体安排:第一章 数组part01
  • 6月1日星期日今日早报简报微语报早读
  • Python6.1打卡(day33)
  • LeetCode 热题 100 155. 最小栈
  • Broker、Proxy、Agent的区别
  • 用提示词写程序(3),VSCODE+Claude3.5+deepseek开发edge扩展插件V2
  • C++ 开发,将数值转换为字符串问题,不能直接拼接引号
  • HarmonyOS NEXT~鸿蒙开发工具CodeGenie:AI驱动的开发效率革命
  • 火语言UI组件--文件对话框
  • chrome.runtime.sendMessage 和 new FormData()
  • SRD-12VDC-SL-C 继电器‌接线图解
  • golang -- slice 底层逻辑
  • 针对 Harmony-Cordova 性能优化,涵盖原生插件开发、线程管理和资源加载等关键场景
  • 某航后缀混淆逆向与顶像风控分析
  • 第十五章 访问控制
  • DelphiXe12创建DataSnap REST Application
  • 深度学习篇---face-recognition的优劣点
  • 计算机视觉---YOLOv5
  • 多模态大语言模型arxiv论文略读(102)
  • HackMyVM-Jabita
  • AI精准挖掘SEO关键词策略
  • Spring Security安全实践指南
  • 《操作系统真相还原》——进入内核
  • NodeJS全栈开发面试题讲解——P11消息队列(MQ)
  • 杨校老师竞赛课之GESP一级C++[2024-12]真题及题解
  • git 学习
  • Leetcode 3567. Minimum Absolute Difference in Sliding Submatrix