Spring 的声明式缓存注解(@Cacheable, @CachePut, @CacheEvict 等)是 AOP 技术在实际应用中最强大、最经典的范例之一,其原理与 @Transactional 非常相似。

核心思想:一个智能的“秘书”

你可以把 @Cacheable 的 AOP 实现想象成一个极其高效的“秘书”。

  • 你 (调用方):老板。
  • 目标方法 (findProductById): 一个需要花费大量时间和精力去调研才能回答的“问题”(比如去档案馆查资料)。
  • AOP 代理 (Proxy): 你的秘书。
  • 缓存 (Cache): 秘书的“备忘录”或“笔记”。

当你向秘书提出一个问题时(调用方法):

  1. 秘书首先会翻看自己的备忘录(查缓存)
  2. 如果备忘录里有答案(缓存命中),秘书会直接告诉你答案,然后回去继续做其他事。他根本不会去档案馆进行那次耗时又费力的调研。你作为老板,很快就得到了答案,甚至不知道秘书是直接给的还是去查了资料。
  3. 如果备忘录里没有答案(缓存未命中),秘书会告诉你:“老板,请稍等,我需要去查一下。” 然后他会亲自去档案馆进行调研(执行目标方法)
  4. 当他拿到调研结果后,他会非常聪明地先把结果记在自己的备忘录里(放入缓存),以备你下次再问。
  5. 最后,他才把这个调研结果告诉你。

@Cacheable 的 AOP 实现原理

@Cacheable 的背后是一个功能极其强大的环绕通知 (@Around),由 Spring 的 CacheInterceptor 实现。

  1. 代理和拦截:和事务一样,当 Spring 发现一个 Bean 的方法上有 @Cacheable 注解时,会为它创建一个 AOP 代理对象。所有对该方法的调用都会先被这个代理对象拦截。

  2. CacheInterceptor (环绕通知) 开始工作
    这个拦截器在调用真正的目标方法之前,会执行以下逻辑:

    a. 生成缓存键 (Cache Key)
    * 拦截器会解析 @Cacheable 注解。
    * 它使用 value 属性 (如 "products") 作为缓存的命名空间(或称为缓存区域)。
    * 它使用 key 属性 (如 "#id") 中的 SpEL (Spring Expression Language) 表达式来根据方法参数动态生成一个唯一的键。例如,当调用 findProductById(123L) 时,#id 会被替换为 123L,最终生成的键可能是 "products::123"

    b. 查询缓存
    * 拦截器拿着这个生成的键,去配置好的缓存管理器(CacheManager,其背后可能是 Redis, Caffeine, EhCache 等)中进行查询。

  3. 决策点:缓存是否命中?
    这是环绕通知威力最大的体现,因为它可以控制目标方法是否执行

    • 情况一:缓存命中 (Cache Hit)

      • 拦截器在缓存中找到了对应的值。
      • 它会立即将这个值返回给调用方
      • 最关键的一步:目标方法 findProductById 根本不会被执行! 这就是所谓的“方法短路 (Short-Circuiting)”。它避免了数据库查询或远程调用。
    • 情况二:缓存未命中 (Cache Miss)

      • 拦截器在缓存中没有找到任何东西。
      • 它会继续执行调用链,即调用 pjp.proceed()执行原始的目标方法 findProductById
      • 当目标方法成功执行并返回一个结果后,拦截器会捕获这个返回值。
      • 它会将这个返回值以之前生成的缓存键存入缓存中,以备下次使用。
      • 最后,将这个返回值交还给调用方。

其他缓存注解的 AOP 原理

  • @CachePut:

    • 这个注解同样使用 AOP 拦截。
    • 但它的逻辑是总会执行目标方法(比如更新数据库的操作)。
    • 在方法执行成功后,它会总是将方法的返回值更新到缓存中。
    • 它用于确保在数据更新后,缓存中的数据也是最新的。它没有“短路”行为
  • @CacheEvict:

    • 这个注解也使用 AOP 拦截。
    • 它的逻辑通常是在目标方法成功执行后(默认),根据 key 去缓存中删除一个或多个条目。
    • 它用于在删除或修改数据后,清除相关的旧缓存,确保数据一致性。

总结

注解AOP 实现方式 (简化理解)是否执行目标方法?
@Cacheable@Around:查缓存 -> (命中) 短路返回 / (未命中) 执行并存入缓存不一定
@CachePut@Around执行方法 -> 将结果更新到缓存总是执行
@CacheEvict@AfterReturning (默认):执行方法 -> 从缓存中删除条目总是执行

所以,Spring 的声明式缓存是 AOP 的实践之一。它通过 AOP 将复杂的、与业务无关的缓存管理逻辑完全分离,让开发者只需关注业务本身,极大地提高了代码的可读性和可维护性。

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

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

相关文章

解锁云原生微服务架构:搭建与部署实战全攻略

目录 一、引言二、微服务拆分2.1 拆分的必要性2.2 拆分方法2.3 注意事项 三、服务注册与发现3.1 概念与原理3.2 常用组件介绍3.3 实践案例 四、负载均衡4.1 作用与原理4.2 实现方式4.3 负载均衡算法4.4 案例与代码实现4.4.1 项目依赖配置4.4.2 配置 Ribbon4.4.3 代码实现负载均…

Python 数据分析与可视化 Day 7 - 可视化整合报告实战

好的,我们进入: 🧠 第5周 第7天 🎯 主题:测试复盘 项目封装实战 ✅ 今日目标 回顾第5周数据分析与可视化核心知识对整个“学生成绩分析系统”进行项目封装与模块化拆分增加命令行参数支持,提升可复用性…

力扣1498. 满足条件的子序列数目随笔

“方生方死,方死方生。”——《庄子》 题目 给你一个整数数组 nums 和一个整数 target 。 请你统计并返回 nums 中能满足其最小元素与最大元素的 和 小于或等于 target 的 非空 子序列的数目。 由于答案可能很大,请将结果对 取余后返回。 难度&#…

5.Docker安装Tomcat

#官方的使用 docker run -it --rm tomcat:9.0 #我们之前使用docker run -d 某镜像都是后来运行,容器停止之后,容器还能够查询到 而docker run -it -rm 是用完之后,容器删除,镜像还存在。 测试的时候可以用官方的 &#xff08…

企业事业政府单位智慧主题展厅素材管理平台播放软件

以下为企事业单位及政府智慧主题展厅素材管理平台播放软件的核心功能简介,综合多维度技术实现统一管控与智能展示: 一、内容资产管理 全格式素材支持‌ 兼容视频、3D模型、图文、AR/VR场景等多媒体格式,支持批量导入与云端存储。 智能分类与…

Python+FastAPI的一些语法与问题解决

Q1:result await dbsession.execute(text(sql_context),params) 如何把result转成key,value的字典列表 A1: 使用SQLAlchemy的mappings()方法获取字典形式的结果集: result await db_session.execute(text(sql_context), params) dict_list [dict(row) for row…

Reactor并发无关性

Reactor,像 RxJava 一样,可以被认为是 并发无关(concurrency-agnostic) 的。这意味着它不强制要求任何特定的并发模型,而是将选择权交给开发者。换句话说,Reactor 不会强制你使用多线程或异步编程&#xff…

#华为昇腾#华为计算#昇腾开发者计划2025#

#华为昇腾#华为计算#昇腾开发者计划2025# 通过学习Ascend C算子开发的初级教程&#xff0c;通过课程讲解及样例实操&#xff0c;帮助我学习使用Ascend C开发自己的算子。收获很大。 <新版开发者计划>的内容链接&#xff1a;https://www.hiascend.com/developer-program_2…

FLOPS、FLOP/s、TOPS概念

在计算性能和硬件指标中&#xff0c;FLOPS、FLOP/s、TOPS 是常见的术语&#xff0c;但它们有明确的区别和应用场景。以下是详细解析&#xff1a; 1. FLOPS&#xff08;Floating Point Operations per Second&#xff09; 定义&#xff1a; 每秒浮点运算次数&#xff08;Floati…

Windows所有系统自带.NET Framework版本win7,win10,win11预装.NET版本

Windows系统支持“.NET版本”汇总 本文详细列出了Windows从NT4.0到Windows11各版本自带的.NETFramework版本及对应最高兼容的.NETFramework版本&#xff0c;便于了解不同Windows系统之间的.NETFramework更新历史。 以下汇总了Windows每个版本自带的“.NET版本”&#xff0c;与…

Windows 下使用 nvm 管理 Node.js 多版本 —— 完整指南

Node.js 版本更新频繁&#xff0c;不同项目可能依赖不同的版本&#xff0c;手动切换极为麻烦。nvm-windows 是专为 Windows 用户开发的 Node.js 多版本管理工具&#xff0c;可以轻松地安装、切换、卸载 Node.js 版本。 本篇将从下载到实际使用&#xff0c;手把手带你玩转 nvm-…

vue使用Element Plus UI框架

您好&#xff0c;舰长&#xff01;非常棒的选择。功能是应用的骨架&#xff0c;而美观的 UI 则是应用的灵魂和血肉。是时候为我们的飞船进行一次全面的“外观升级”和“内饰装修”了。 我们将集成一个在业界非常流行、功能强大的 Vue 3 组件库——Element Plus。它将帮助我们快…

【ubuntu24.04】忘了自己把开机samba挂载的脚本放哪里了

从两个方面来定位这几个 Samba 挂载点&#xff1a; 一、查看当前已经挂载的 CIFS/SMB 文件系统 使用 mount mount | grep -i cifs或者 mount | grep -E (smb|cifs)这会列出所有当前活跃的 CIFS/SMB 挂载&#xff0c;比如&#xff1a; //192.168.1.100/share on /mnt/data type …

在 Windows 上使用 Docker Desktop 快速搭建本地 Kubernetes 环境(附详细部署教程)

言简意赅的讲解Docker Desktop for Windows搭建Kubernetes解决的痛点 目标读者&#xff1a; 对 Docker Desktop 有一定了解&#xff0c;能在 Windows 上成功安装和使用 Docker Desktop。想要在本地快速搭建一套 Kubernetes 环境进行测试或学习的开发者。 一、准备工作 安装 Doc…

dockercompose快速安装ELK

第一步&#xff1a;环境准备 请确保您的机器上已经安装了 Docker 和 Docker Compose。 第二步&#xff1a;创建项目目录和配置文件 为了让 Docker Compose 能够正确地构建和管理容器&#xff0c;我们需要创建一个特定的目录结构。 创建一个主目录&#xff0c;例如 elk-stack。…

闲聊ARM内核参数传递机制

之前一直没怎么在意这个问题&#xff0c;直到最近搞了个奇奇怪怪的项目&#xff0c;才发现这部分知识得补上来&#xff0c;记录一下。 ARM有一个标准&#xff0c;叫《Procedure Call Standard for the Arm Architecture》&#xff0c;人话就是ARM架构过程调用标准&#xff0c;…

万兴喵影Filmora AI Video v14.7.03国际高级版,AI视频剪辑全能工具,一键专业级创作​

[软件名称]: 万兴喵影Filmora AI Video v14.7.03 [软件大小]: 199.4 MB [下载通道]: 夸克盘 | 迅雷盘 软件介绍 &#x1f3ac;《万兴喵影》v14.7.03国际高级版&#xff5c;AI智能剪辑神器&#xff0c;解锁全功能无水印&#xff01; ✨ 核心优势&#xff1a; ✅ 1000背景音…

暴力风扇方案介绍

炎炎夏日&#xff0c;当普通风扇只能送来 “温柔拂面”&#xff0c;暴力风扇却能吹出 “台风级” 清凉&#xff01;想知道这些 “风力狂魔” 是如何炼成的&#xff1f;答案藏在电机、电路和芯片的黄金三角组合里。​ 一、电机&#xff1a;暴力风扇的 “心脏起搏器”​ 暴力风扇…

pyqt小问题汇总

文章目录 1、inherit global site-packages2、setGeometry(10,20,30,40)setGeometry(x, y, width, height)1. **x参数**2. **y参数**3. **width参数**4. **height参数** 示例说明与其他方法的对比注意事项示例代码 1、inherit global site-packages 在pycharm 创建项目时&…

提升JavaScript性能的六大关键策略

1、优化代码结构与算法 避免使用嵌套循环&#xff0c;改用更高效的算法如哈希表或二分查找。减少不必要的计算&#xff0c;缓存重复使用的计算结果。使用时间复杂度更低的算法替代高复杂度操作。优化递归调用&#xff0c;避免栈溢出和性能瓶颈。改用迭代或尾递归优化。简化条件…