一、@Cacheable 注解
作用:将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中获取,不用调用方法:
属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | value/cacheNames:指定缓存组件的名字; CacheManager 管理多个 Cache 组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字 key: 缓存数据使用的 key,可以用它来指定。默认是使用方法参数的值。如 id= 1 , 1 ——>方法的返回值 使用SPEL表达式:#id 是参数 id 的值 #a0 #p0 #root.arg[ 0 ] keyGenerator:key 的生成器,可以自己指定 key 的生成器的组件 id key 与 keyGenerator 二选一使用 cacheManager:指定缓存管理器;或者是 cacheResolver condition:判断条件,指定符合条件的情况下才缓存 unless:否定,unless 指定的条件为 true ,方法的返回值就不会被缓存,可以获取到结果进行判断 unless = "#result == null" sync:是否使用异步模式 |
代码示例:
@Cacheable(cacheNames = {"emp"})
public Employee getEmpById(Integer id) {
System.out.println("查询" + id +"号员工");
return employeeMapper.getEmpById(id);
}
二、@Cacheable 原理
当在主程序类上使用了 @EnableCaching 注解就可以开启基于注解的缓存,下面来分析一下缓存的原理。
1、自动配置类 CacheAutoConfiguration
给容器中导入 CacheConfigurationImportSelector 类。
2、CacheConfigurationImportSelector 给容器中导入一系列的缓存的配置类
导入的自动配置类:
3、查看那个配置类默认生效
在配置文件中使用 debug = true 打开配置报告
默认是 SimpleCacheConfiguration 缓存配置类生效。
4、SimpleCacheConfiguration 作用
SimpleCacheConfiguration 给容器中注册了一个CacheManager: ConcurrentMapCacheManager
5、ConcurrentMapCacheManager 作用
ConcurrentMapCacheManager 实现了 CacheManager 接口,并重写了其中的方法:
ConcurrentMapCacheManager 作用:
(1)可以获取和创建 ConcurrentMapCache 类型的缓存组件;
(2)他的作用是将数据保存到 ConcurrentMap 中;
6、ConcurrentMapCache 类
用于缓存数据的类,其中使用 ConcurrentMap 来缓存数据。
存放值的方法:
三、运行流程
以 @Cacheable 注解为例:
1、方法运行之前,先去查询 Cache(缓存组件),按照 cacheNames 指定的名字获取(CacheManager先获取相应的缓存),第一次获取缓存组件如果没有 Cache 组件会自动创建;
2、去 Cache 中查找缓存的内容,使用一个 key(默认就是方法的参数),key 是按照某种策略生成的 ,默认是使用 keyGenerator 生成的,默认使用 SimpleKeyGenerator 生成 key;
SimpleKeyGenerator 生成 key 的默认策略
1 2 3 4 5 | 如果没有参数:key = new SimpleKeyGenerator 如果有一个参数: key = 参数的值 如果有多个参数:key = new SimpleKey(param); |
3、没有查到缓存就调用目标方法;
4、将目标方法返回的结果,放进缓存中
@Cacheable 标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为 key 去查询,如果没有就运行方法,并将结果放入缓存中,以后再来调用就可以直接使用缓存中的数据。
核心:
(1)使用 CacheManager【ConcurrentMapCacheManager】 按照名字得到 Cache 【ConcurrentMapCache】组件;
(2)key 是使用 keyGenerator 生成的,默认是 SimpleKeyGenerator 生成的;
四、常用属性
1、value/cacheNames
指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存
示例:
@Cacheable(cacheNames = {"emp", "temp"})
public Employee getEmpById(Integer id) {
System.out.println("查询" + id +"号员工");
return employeeMapper.getEmpById(id);
}
2、key: 缓存数据使用的 key
支持使用 Spel 表达式
1 2 | 使用SPEL表达式:#id 是参数 id 的值 #a0 #p0 #root.arg[ 0 ] getEmp[ 1 ] 作为 key key = "#root.methodName + '[' + #id + ']'" |
Spel 表达式:
3、keyGenerator:key 的生成器
key 与 keyGenerator 二选一使用,可以自定义keyGenerator
自定义 KeyGenerator:
@Configuration
public class MyCacheConfig {
@Bean(value = "myKeyGenerator")
public KeyGenerator keyGenerator() {
return new KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
return method.getName() + "[" + Arrays.asList(params).toString() + "]";
}
};
}
}
@Cacheable(cacheNames = {"emp"}, keyGenerator = "myKeyGenerator")
public Employee getEmpById(Integer id) {
System.out.println("查询" + id +"号员工");
return employeeMapper.getEmpById(id);
}
4、condition:判断条件,指定符合条件的情况下才缓存
1 2 | condition = "#a0 > 1" 当第一个参数的值 > 1 的时候才进行缓存 condition = "#a0 > 1 and #root.methodName eq 'getEmpById'" 第一个参数的值 > 1 并且方法名是 getEmpById |
5、unless:否定,unless 指定的条件为 true,方法的返回值就不会被缓存,可以获取到结果进行判断
1 2 | unless = "#result == null" 方法返回值如果为 null ,结果不缓存 unless = "#a0 == 2 " 如果第一个参数的值是 2 ,结果不缓存 |
示例:
@Cacheable(cacheNames = {"emp"}, keyGenerator = "myKeyGenerator", condition = "#a0 > 1", unless = "#a0 == 2 ")
public Employee getEmpById(Integer id) {
System.out.println("查询" + id +"号员工");
return employeeMapper.getEmpById(id);
}
6、sync:是否使用异步模式
#unless()} is not supported 开启异步,不支持 unless
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战