目录
四、@Cacheable、@CachePut、@CacheEvict 主要的参数
1、Spring Cache提供了一些供我们使用的SpEL上下文数据
一、JSR107
- Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
- CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider
- CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
- Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
- Entry是一个存储在Cache中的key-value对。
- Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
二、Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;
- Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
- Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等;
- 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取
- 方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
使用Spring缓存抽象时我们需要关注以下两点;
- 确定方法需要被缓存以及他们的缓存策略
- 从缓存中读取之前缓存存储的数据
三、重要概念及缓存注解
名称 | 解释 |
---|---|
Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager | 缓存管理器,管理各种缓存(cache)组件 |
@Cacheable | 主要针对方法配置,能够根据方法的请求参数对其进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存。 与@Cacheable区别在于是否每次都调用方法,常用于更新 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据时key生成策略 |
serialize | 缓存数据时value序列化策略 |
@CacheConfig | 统一配置本类的缓存注解的属性 |
四、@Cacheable、@CachePut、@CacheEvict 主要的参数
名称 | 解释 |
---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#id”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
allEntries (@CacheEvict ) | 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation (@CacheEvict) | 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true) |
五、SpEL上下文数据
1、Spring Cache提供了一些供我们使用的SpEL上下文数据
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
2、注意:
当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如
@Cacheable(key = "targetClass + methodName +#p0")
使用方法参数时我们可以直接使用“#参数名”或者#${p参数index}”。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
3、SpEL运算符
类型 | 运算符 |
---|---|
关系 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne |
算术 | +,- ,* ,/,%,^ |
逻辑 | &&,||,!,and,or,not,between,instanceof |
条件 | ?: (ternary),?: (elvis) |
正则表达式 | matches |
其他类型 | ?.,?[…],![…],^[…],$[…] |
六、实例应用
项目参考本博客:https://blog.csdn.net/s294878304/article/details/99118548
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2、启动类注解@EnableCaching开启缓存
@SpringBootApplication
@EnableCaching
public class SpringbootmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootmybatisApplication.class, args);
}
}
3、缓存@Cacheable
@RequestMapping(value = "/getAnchorBaseInfoByPlatRoomCacheable", method = {RequestMethod.GET})
@Cacheable(value = "anchorinfo" ,key = "targetClass + methodName + #p0 + #p1")
public AnchorBaseInfoBean getAnchorBaseInfoByPlatRoomCacheable(
@ApiParam(value = "平台ID", required = true) @RequestParam(value = "platID", required = true) int platID,
@ApiParam(value = "房间ID", required = true) @RequestParam(value = "roomID", required = true) String roomID
) {
AnchorBaseInfoBean resultBean=anchorBaseInfoDao.getAnchorBaseInfoByPlatRoom(platID,roomID);
return resultBean;
}
(1)、注意:
- @Cacheable内部的
value
是必需的,它指定了缓存存放在哪块命名空间。 - 此处的
key
是使用的spEL表达式。这里有一个小坑,如果你把methodName
换成method
运 行会报错,观察它们的返回类型, - 原因在于
methodName
是String
而methoh
是Method
。 - 此处的
User
实体类一定要实现序列化public class User implements Serializable
,否则会报java.io.NotSerializableException
异常。
(2)、验证缓存是否生效方法:
在AnchorBaseInfoServiceImpl类中添加代码,重复访问接口,看控制台是否多次打印
http://localhost:8080/anchor/getAnchorBaseInfoByPlatRoomCacheable?platID=2&roomID=1023513
@Service
public class AnchorBaseInfoServiceImpl implements AnchorBaseInfoService {
@Autowired
private AnchorBaseInfoDao anchorBaseInfoDao;
@Override
public AnchorBaseInfoBean getAnchorBaseInfoBean(int platform_id,String room_id)
{
System.out.println("###############使用cache后,验证是否再次访问数据库");
AnchorBaseInfoBean anchorBaseInfoBean=anchorBaseInfoDao.getAnchorBaseInfoByPlatRoom(platform_id,room_id);
return anchorBaseInfoBean;
}
}
(3)、打开@Cacheable
注解的源码,查看它的其它属性
String[] cacheNames() default {}; //和value注解差不多,二选一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则缓存
String unless() default ""; //条件符合则不缓存
boolean sync() default false; //是否使用异步模式
4、配置@CacheConfig
当我们需要缓存的地方越来越多,可以使用@CacheConfig(cacheNames = {"myCache"})
注解来统一指定value
的值,这时可省略value
,
如果你在你的方法依旧写上了value
,那么依然以方法的value
值为准。
package com.example.controller;@RestController
@RequestMapping(value="/anchor", produces = "application/json; charset=UTF-8")
@CacheConfig(cacheNames = {"mycache"})
public class AnchorBaseInfoController {
@Autowired
private AnchorBaseInfoService anchorBaseInfoService;
@Autowired
private AnchorBaseInfoDao anchorBaseInfoDao;
@RequestMapping(value = "/getAnchorBaseInfByPlatRoomCacheConfig", method = {RequestMethod.GET})
@Cacheable(value = "anchorinfo" ,key = "targetClass + methodName + #p0 + #p1")
public AnchorBaseInfoBean getAnchorBaseInfByPlatRoomCacheConfig(
@ApiParam(value = "平台ID", required = true) @RequestParam(value = "platID", required = true) int platID,
@ApiParam(value = "房间ID", required = true) @RequestParam(value = "roomID", required = true) String roomID
) {
AnchorBaseInfoBean resultBean=anchorBaseInfoDao.getAnchorBaseInfoByPlatRoom(platID,roomID);
return resultBean;
}
}
5、@CachePut 更新
@CachePut
注解的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存。- 和
@Cacheable
不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。 - 需要注意的是该注解的
value
和key
必须与要更新的缓存相同,也就是与@Cacheable
相同。
@RequestMapping(value = "/getAnchorBaseInfoByPlatRoomCacheable", method = {RequestMethod.GET})
@Cacheable(value = "anchorinfo" ,key = "targetClass + methodName + #p0 + #p1")
public AnchorBaseInfoBean getAnchorBaseInfoByPlatRoomCacheable(
@ApiParam(value = "平台ID", required = true) @RequestParam(value = "platID", required = true) int platID,
@ApiParam(value = "房间ID", required = true) @RequestParam(value = "roomID", required = true) String roomID
) {
AnchorBaseInfoBean resultBean=anchorBaseInfoDao.getAnchorBaseInfoByPlatRoom(platID,roomID);
return resultBean;
}
@RequestMapping(value = "/getAnchorBaseInfoByPlatRoomCachePut", method = {RequestMethod.GET})
@Cacheable(value = "anchorinfo" ,key = "targetClass + methodName + #p0 + #p1")
public AnchorBaseInfoBean getAnchorBaseInfoByPlatRoomCachePut(
@ApiParam(value = "平台ID", required = true) @RequestParam(value = "platID", required = true) int platID,
@ApiParam(value = "房间ID", required = true) @RequestParam(value = "roomID", required = true) String roomID
) {
AnchorBaseInfoBean resultBean=anchorBaseInfoDao.getAnchorBaseInfoByPlatRoom(platID,roomID);
return resultBean;
}
6、清除@CacheEvict
@CacheEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。
@CacheEvict 当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。
属性 | 解释 | 示例 |
---|---|---|
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value=”testcache”,beforeInvocation=true) |
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
System.out.println("delete user by id: " + id);
}
7、@Caching 组合
有时候我们可能组合多个Cache注解使用,此时就需要@Caching组合多个注解标签了。
@RequestMapping("/hello")
@Caching(
cacheable = {
@Cacheable(value = "", key="")
},
put = {
@CachePut(value = "",key = "")
},
evict = {
@CacheEvict(value = "",key="")
}
)
public String hello(){
return "hello world!!";
}