【Spring Cache】二 Spring 缓存操作相关注解及属性
前言
本章节了解一下 Spring
定义的缓存相关注解 @Cacheable
@CachePut
@CacheEvict
@Caching
@CacheConfig
,并了解相关属性
@Cacheable
/**
* Cacheable 表明开启缓存行为,如果标注类上就表示缓存所有方法
* 缓存 key 基于参数生成,也可以指定 SpEL 表达式,或者自定义 KeyGenerator
* 如果没有获取到缓存结果,就将方法执行的结果缓存进去,如果方法返回值类型为
* Optional,缓存的会是实际值
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
@AliasFor("cacheNames")
String[] value() default {};
// 用于匹配缓存的目标 cache name
@AliasFor("value")
String[] cacheNames() default {};
/**
* 支持 SpEL 表达式指定 key,默认为空,则基于 keyGenerator 生成,
* 若未指定 keyGenerator,则基于参数生成
* SpEL 的 context 提供如下参数
* #root.method:目标方法
* #root.target:目标对象
* #root.caches:目标 Cache
* #root.methodName:方法名称简写
* #root.targetClass:目标 Class
* 目标参数的获取有:#root.args[1] || #p1 || #a1
*/
String key() default "";
// 自定义 KeyGenerator 的 beanName,与 key 属性互斥
String keyGenerator() default "";
// 如果没有指定 cacheResolver,则基于这个 CacheManager 的 beanName 获取
// 与 cacheResolver 属性互斥
String cacheManager() default "";
// 自定义 CacheResolver 的 beanName
String cacheResolver() default "";
// 基于 SpEL 的 条件表达式,指定缓存触发的条件,默认为空,即无条件触发
String condition() default "";
/**
* 基于 SpEL 对方法执行结果的缓存条件判断
* 默认为空意味着无条件缓存结果
* 在之前 context 的基础上还可以访问
* #result:方法执行结果,对于Optional 返回值它获取的是实际值
*/
String unless() default "";
/**
* 表明目标方法是否在并发环境下支持同步操作,开启时受到如下限制:
* 1)不支持 unless 属性
* 2)只能针对一个缓存,由 cacheNames 属性指定
* 3)不支持同时有其他操作,或者多个 Cacheable 合并
* 但究竟是否支持缓存同步其实还是取决于底层供应商的实现
*/
boolean sync() default false;
}
- 如果标注在类上则标识所有方法,如果标注在方法上则标识目标方法,开启缓存操作
- 该缓存操作会在执行目标方法前先从目标缓存中获取,获取不到才会执行目标方法,然后将结果缓存
- 提供了大量属性:
value & cacheNames
:用于匹配缓存目标Cache
的name
key & keyGenerator
:用于解析cacheKey
,key
属性允许指定一个SpEL
表达式来计算cacheKey
,如果未指定则会基于自定义的keyGenerator
生成,如果都没有则会基于参数生成,不难理解key
和keyGenerator
是互斥的cacheManager & cacheResolver
:也是一对互斥的属性,当未提供cacheResolver
时会尝试基于cacheManager
解析对应的cacheResolver
condition & unless
:基于SpEL
计算的条件表达式,区别是后者基于方法返回值决定是否缓存,因此其Expression Context
中额外包含#result
变量sync
:表示是否支持同步操作,最终由具体的Provider
提供支持
@CachePut
/**
* 缓存目标类上所有或指定方法
* 与 @Cacheable 不同的是,只要满足 condition & unless 就触发,
* 而不会先去目标 Cache 查一遍
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
String unless() default "";
}
- 类似于
@Cacheable
,该注解标识对应方法开启缓存插入操作,区别在于此操作不会去判断缓存是否存在,即只基于condition & unless
决定是否缓存 - 其属性基本都了解过了,它并不提供
sync
操作,即不支持同步操作
@CacheEvict
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// 该注解表示类上所有或指定方法会对目标缓存执行剔除操作
public @interface CacheEvict {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
/**
* 是否移除目标 Cache 的所有缓存,默认 false 意味着只清除指定 key
* 的缓存,为 true 时就不允许指定 key 属性了
*/
boolean allEntries() default false;
/**
* 剔除缓存操作是否发生在方法执行前
* 默认 false 表示只有目标方法 成功 执行才会进行剔除操作
* true 则表示先剔除,不管方法执行结果如何
*/
boolean beforeInvocation() default false;
}
- 该注解开启目标方法的缓存剔除操作
- 基于之前了解的属性拓展了:
allEntries
:标识是否清空目标缓存,默认false
只移除指定缓存,该属性为true
时就不允许指定key
属性了beforeInvocation
:标识是否在目标方法执行前进行剔除操作,默认false
即目标方法执行成功后才进行移除,否则在目标方法执行前移除(无视方法是否执行成功)
@Caching
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// 这个注解主要是针对一个方法上支持一组相(不)同缓存操作的场景
public @interface Caching {
Cacheable[] cacheable() default {};
CachePut[] put() default {};
CacheEvict[] evict() default {};
}
该注解用于标识一系列缓存行为
@CacheConfig
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 在类级别用于提供默认缓存配置
public @interface CacheConfig {
String[] cacheNames() default {};
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
}
- 该注解用于类上,为其下所有的缓存操作提供一份默认配置
- 主要提供属性
cacheNames
keyGenerator
cacheManager
cacheResolver
KeyGenerator
@FunctionalInterface
public interface KeyGenerator {
// 基于 target method params 生成 key
Object generate(Object target, Method method, Object... params);
}
- 上述注解中指定的
keyGenerator
即对应KeyGenerator
对应实例的beanName
- 它基于
target
method
params
为目标缓存操作生成指定的key
Spring Cache
提供的内置实现SimpleKeyGenerator
,基于参数生成对应的SimpleKey
CacheResolver
@FunctionalInterface
public interface CacheResolver {
// 基于 CacheOperationInvocationContext 获取对应的 Cache 集合
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
}
用于解析目标缓存操作对应的 Cache
集合
AbstractCacheResolver
public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean {
@Nullable
private CacheManager cacheManager;
// ...
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
// 基于 CacheOperationInvocationContext 获取 cacheNames
Collection<String> cacheNames = getCacheNames(context);
if (cacheNames == null) {
return Collections.emptyList();
}
// 基于 cacheNames 从 CacheManager 获取对应的 Cache 集合
Collection<Cache> result = new ArrayList<>(cacheNames.size());
for (String cacheName : cacheNames) {
Cache cache = getCacheManager().getCache(cacheName);
result.add(cache);
}
return result;
}
// 子类实现,基于 CacheOperationInvocationContext 获取对应的 cacheNames
@Nullable
protected abstract Collection<String> getCacheNames(CacheOperationInvocationContext<?> context);
}
CacheResolver
的抽象实现:
- 需要指定一个
CacheManager
getCacheNames
基于CacheOperationInvocationContext
获取对应的cacheNames
- 基于上述
cacheNames
,由CacheManager
获取对应的Cache
集合
SimpleCacheResolver
public class SimpleCacheResolver extends AbstractCacheResolver {
// ...
// 从 CacheOperation 中获取
@Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
return context.getOperation().getCacheNames();
}
// ...
}
Spring Cache
提供的内置实现,其中getCacheNames
方法从对应的CacheOperation
中获取cacheNames
CacheOperationInvocationContext
即整个缓存操作方法执行的上下文信息,在后续的文章会具体了解
总结
本章节的内容都是定义性的注解及辅助的属性类,因此没有给出具体的示例 demo
,但这些类穿插在后续的 Spring Cache
细节中
上一篇:【Spring Cache】一 Cache CacheManager
下一篇:【Spring Cache】三 CacheOperationInvocationContext CacheOperationExpressionEvaluator