一.Spring Cache
1.概述
Spring框架支持透明地向应用程序添加缓存.抽象的核心是将缓存应用于方法,从而根据缓存中可用的信息减少数据库访问的次数.
缓存逻辑是透明地应用的,不会对调用程序造成任何干扰.
只要通过@EnableCaching注释启用缓存支持,Spring Boot就会自动配置缓存基础设施.
2.支持的缓存
缓存抽象不提供实际的存储,而是依赖于org.springframework.cache 和 org.springframework.cache.CacheManager 接口
- Generic
- JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
二.几个重要概念:
序号 | 名词 | 说明 |
---|---|---|
01 | Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
02 | CacheManager | 缓存管理器,管理各种缓存(cache)组件 |
03 | keyGenerator | 缓存数据时key生成策略 |
04 | serialize | 缓存数据时value序列化策略 |
三.几个重要注解:
序号 | 注解 | 说明 |
---|---|---|
01 | @EnableCaching | 开启基于注解的缓存 |
02 | @Cacheable | 主要针对方法配置,能够根据方法的请求参数对其进行缓存 |
03 | @CachePut | 保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新. |
04 | @CacheEvict | 清空缓存 |
05 | @CacheConfig | 统一配置本类的缓存注解的属性 |
06 | @Caching | 混合注解 |
四.几个重要参数:
@Cacheable/@CachePut/@CacheEvict 主要的参数
序号 | 参数 | 说明 |
---|---|---|
01 | value | cacheNames的别名.即缓存的名称 |
02 | cacheNames | 同value |
03 | key | 缓存的key,支持SPEL表达式.默认为"" |
04 | keyGenerator | key生成器,默认使用SimpleKeyGenerator,即根据Key数组生成一个字符串 |
05 | cacheManager | cache管理器 |
06 | cacheResolver | 自定义CacheResolver的bean名称 |
07 | condition | 满足某个条件时执行,支持SPEL表达式 |
08 | unless | 满足某个条件时不执行,支持SPEL表达式.否定缓存, 当条件为 true 时, 就不会缓存. |
09 | sync | 是否异步执行 |
10 | allEntries | @CacheEvict独有,是否清空所有的缓存 |
11 | beforeInvocation | @CacheEvict独有,是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 |
五.缓存SpEL可用元数据
序号 | 名称 | 位置 | 说明 | 举例 |
---|---|---|---|---|
01 | methodName | Root object | 当前被调用的方法名 | #root.methodName |
02 | method | Root object | 当前被调用的方法 | #root.method.name |
03 | target | Root object | 当前被调用的目标对象 | #root.target |
04 | targetClass | Root object | 当前被调用的目标对象类 | #root.targetClass |
05 | args | Root object | 当前被调用的方法的参数列表 | #root.args[0] |
06 | caches | Root object | 当前方法调用使用的缓存列表(如@Cacheable(value={“cache1”, “cache2”})),则有两个cache | #root.caches[0].name |
07 | Argument name | Evaluation context | 当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数 | #iban or #a0 (you can also use #p0 or #p<#arg> notation as an alias). |
08 | result | Evaluation context | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless','cache evict'的beforeInvocation=false) | #result |
六.SpringBoot使用
1.加入依赖
使用之前需要加入以下依赖:
org.springframework.boot
spring-boot-starter-cache
2.开启自动配置
开启缓存
@EnableCaching
@SpringBootApplication
public class SpringBootCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCacheApplication.class, args);
}
}
3.使用 @Cacheable
使用 @Cacheable 注解后, 调用 findByName 会先从缓存中查找是否有对应的数据, 如果没有才会去数据库查找, 并将查找的结果放入缓存中.如果在缓存中查询到数据则不会访问方法体重的代码.
1.方法运行事前, 先去查询 Cache(缓存组件),按照 cacheNames 指定的名字获取:
(CacheManager 先获取相应的缓存),第一次获取缓存如果没有 Cache 组件会自动创建.
2.去 cache 中查找缓存的内容,使用一个 key ,默认就是方法的参数:
key 是按照某种策略生成的,默认使用的 keyGenerator生成的,默认使用 SimpleKeyGenerator 生成 key
SimpleKeyGenerator 生成 key 的默认策略:
如果没有参数, key = new SimpleKey()
如果只有一个参数, key = 参数的值
如果有多个参数, key = new SimpleKey(params)
3.没有查询到缓存就调用目标方法:
4.将目标方法返回的结果放进缓存中.
@Cacheable
public ReturnDO findByName(String name) {
log.info("UserDetailService|findByName|{}", name);
UserDetailDO userDetailDO = repository.findUserCacheDOByNameIs(name);
return ReturnDO.builder().data(userDetailDO).build();
}
4.使用 @CachePut
被标注@CachePut的方法,每次方法被调用均会执行目标方法,并对请求参数对其结果进行缓存,这个注解主要用于新增数据和更新数据上(POST & PUT).
这里的KEY & VALUE必须和 @Cacheable KEY & VALUE 相同.
运行时机:
1.先调用目标方法;
2.将目标方法的结果缓存起来;
@CachePut(key = "#result.data.name")
public ReturnDO update(UserDetailDO userCacheDTO) {
UserDetailDO userDetailDO = repository.save(userCacheDTO);
return ReturnDO.builder().data(userDetailDO).build();
}
5.使用 @CacheEvict
@CacheEvict 的作用是根据一定的条件对缓存进行清空(DELETE),该方法也是每次调用均会执行,删除数据同时删除缓存中的数据
key:指定要清除的数据
allEntries = true:指定清除这个缓存中所有的数据
beforeInvocation = true: 缓存的清除是否在方法之前执行
默认代表缓存清除操作是在方法执行之后执行:如果出现异常缓存就不会清除
beforeInvocation = false: 缓存的清除是否在方法之后执行
无论方法是否出现异常,缓存都清除
@CacheEvict
public ResponseEntity delete(String name) {
repository.deleteUserCacheDOByNameIs(name);
return new ResponseEntity<>(HttpStatus.OK);
}
6.使用 @CacheConfig
方法统一注解,一般注解到类上,表示该类方法中相同的注解配置使用值(统一设置配置).
@Slf4j
@Service
@CacheConfig(cacheNames = "redis_cache")
public class UserDetailService {
7.使用 @Caching
@Caching 复杂缓存配置
@Caching(
cacheable = {
@Cacheable(key = "#a0.name")
},
put = {
@CachePut(key = "#result.data.name"),
@CachePut(key = "#result.data.phone")
}
)
public ReturnDO create(UserDetailDO userCacheDTO) {
UserDetailDO userDetailDO = repository.save(userCacheDTO);
return ReturnDO.builder().data(userDetailDO).build();
}