“Spring 的 Redis缓存注解”的版本间差异
跳到导航
跳到搜索
(→注解详解) |
|||
第153行: | 第153行: | ||
== 注解详解 == | == 注解详解 == | ||
Spring 框架自身并没有实现缓存解决方案,但是从 3.1 开始定义了 '''org.springframework.cache.Cache''' 和 '''org.springframework.cache.CacheManager''' 接口,提供对缓存功能的声明,能够与多种流行的缓存实现集成。 | |||
1、Cache 接口为缓存的组件规范定义,包含缓存的各种操作集合; | |||
Cache 接口下 Spring 提供了各种 xxxCache 的实现,如:RedisCache、EhCacheCache、ConcurrentMapCache 等; | |||
2、CacheManager 接口为缓存管理器规范,简单来说就是用于存放 cache。 | |||
Spring 默认也提供了一些列管理器的实现。 | |||
Spring 缓存抽象提供了 5 个注解用来声明缓存规则: | Spring 缓存抽象提供了 5 个注解用来声明缓存规则: | ||
# @ | # '''@CachePut''':执行方法,并缓存结果。 | ||
# @ | # '''@Cacheable''':能够根据方法的请求参数对其结果进行缓存,多用于查询。 | ||
# @ | # '''@CacheEvict''':清空缓存。 | ||
# @ | # '''@Caching''':能够同时应用多个缓存注解功能。 | ||
# @ | # '''@CacheConfig''':用于抽取缓存的公共配置。【仅类级别】 | ||
* 以上 5 个注解除了 @CacheConfig 注解是类级别的注解,其余 4 个注解在“类”和“方法”上均可以使用: | * 以上 5 个注解除了 @CacheConfig 注解是类级别的注解,其余 4 个注解在“类”和“方法”上均可以使用: | ||
*# 作用在类上:表示对该类下所有方法生效;(但用得较少) | *# 作用在类上:表示对该类下所有方法生效;(但用得较少) | ||
*# 作用在方法上:只对该方法生效;且只能用于 public 修饰的符方法,protected 或者 private 修饰的方法不适用(和配置项的“mode 属性”有关???)。 | *# 作用在方法上:只对该方法生效;且只能用于 public 修饰的符方法,protected 或者 private 修饰的方法不适用(和配置项的“mode 属性”有关???)。 | ||
常用属性说明: | |||
# '''value''' 属性:指定 Cache 缓存的名称。 | # '''value''' 属性:指定 Cache 缓存的名称。 | ||
#* value 值表示当前 Key 键被缓存在哪个 Cache 上(相当于缓存 Key 所属的命名空间),对应于 Spring 配置文件中 CacheManager 缓存管理器的 '''cacheNames''' 属性中配置的某个 Cache | #* value 值表示当前 Key 键被缓存在哪个 Cache 上(相当于缓存 Key 所属的命名空间),对应于 Spring 配置文件中 CacheManager 缓存管理器的 '''cacheNames''' 属性中配置的某个 Cache 名称; | ||
#* 可以设置多个 Cache:配置 value 值为一个数组。(如:“value={userCache,otherCache1,otherCache2}”) | #* 可以设置多个 Cache:配置 value 值为一个数组。(如:“value={userCache,otherCache1,otherCache2}”) | ||
#* '''cacheNames''' 为 value 的别名(Spring 4 新增)。 | |||
# '''key''' 属性:指定 Redis 的 Key 的值。 | # '''key''' 属性:指定 Redis 的 Key 的值。 | ||
#* 当没有指定该属性时,Spring | #* 当没有指定该属性时,Spring 将使用默认策略('''SimpleKeyGenerator''')生成 Key 键: | ||
#*# 如果方法没有给出参数,则返回 SimpleKey.EMPTY;【即:“key = new SimpleKey()”】 | |||
#*# 如果方法只给出一个参数,则返回该参数的值;【即:“key = 参数的值”】 | |||
#*# 如果方法给出了更多的参数,则返回包含所有参数的 SimpleKey;【即:“key = new SimpleKey(params)”】 | |||
#** 当使用默认策略时,相关的参数需要有有效的“hashCode()”和“equals()”方法。 | |||
#* 该属性支持 '''SpringEL''' 表达式。 | #* 该属性支持 '''SpringEL''' 表达式。 | ||
# '''condition''' | # '''condition''' 属性:指定缓存的条件“什么情况缓存”。 | ||
#* | #* 当没有指定该属性时,表示将缓存所有的结果; | ||
#* 该属性支持 '''SpringEL''' 表达式:当表达式的值为 true 时,表示进行缓存处理;否则不进行缓存处理。 | #* 该属性支持 '''SpringEL''' 表达式:当表达式的值为 true 时,表示进行缓存处理;否则不进行缓存处理。 | ||
# '''unless''' 属性:指定缓存的条件“什么情况不缓存”。 | |||
#* 需使用 '''SpringEL''' 表达式; | |||
#* 不同于 condition 属性,该条件是在函数被调用之后才做判断的,所以它可以通过对 result 进行判断。 | |||
# '''sync''' 属性:是否使用'''同步模式'''。 | |||
#* 在多线程环境中,可能会出现相同的参数的请求并发调用方法的操作,默认情况下,spring cache 不会锁定任何东西,相同的值可能会被计算几次,这就违背了缓存的目的。对于这些特殊情况,可以使用 sync 属性。 | |||
#* 若设置为 true:则只有一个线程在处于计算,而其他线程则被阻塞,直到在缓存中更新条目为止。 | |||
# '''keyGenerator''' 属性:指定 key 生成器。 | |||
#* 该属性与 key 属性是互斥的; | |||
#* 自定义的 key 生成器需要实现 '''org.springframework.cache.interceptor.KeyGenerator''' 接口,并使用该参数来指定: | |||
#*: <syntaxhighlight lang="Java" highlight=""> | |||
@Configuration | |||
public class MyCacheConfig { | |||
// 省略其他配置项 | |||
. . . | |||
// 自定义 keyGenerator | |||
@Bean("myKeyGenerator") | |||
public KeyGenerator keyGenerator(){ | |||
return new KeyGenerator(){ | |||
@Override | |||
public Object generate(Object target, Method method, Object... params) { | |||
return method.getName()+"["+ Arrays.asList(params).toString()+"]"; | |||
} | |||
}; | |||
} | |||
} | |||
</syntaxhighlight> | |||
# '''cacheManager''' 属性:用于指定使用哪个缓存管理器。 | |||
#* 只有当配置有多个缓存管理器时才需要使用。 | |||
# '''cacheResolver''' 属性:指定使用的缓存解析器。 | |||
#* 需通过 '''org.springframework.cache.interceptor.CacheResolver''' 接口来实现自己的缓存解析器,并用该参数指定。 | |||
#*: <syntaxhighlight lang="Java" highlight=""> | |||
</syntaxhighlight> | |||
=== @CachePut === | |||
@CachePut:用于'''增加/更新缓存''',每次执行方法后,会将结果存入指定缓存的 Key 键上。 | |||
支持的属性: | |||
# '''value''' | |||
# '''key''' | |||
# '''condition''' | |||
# '''unless''' | |||
# '''sync''' | |||
# '''keyGenerator''' | |||
# '''cacheManager''' | |||
# '''cacheResolver''' | |||
第197行: | 第256行: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== @Cacheable === | === @Cacheable === | ||
第202行: | 第262行: | ||
* 与 @CachePut 注解一样,@Cacheable 也具备增加缓存的能力。 | * 与 @CachePut 注解一样,@Cacheable 也具备增加缓存的能力。 | ||
** 但与 @CachePut 不同之处的是:@CachePut 在方法执行前不去进行缓存检查,无论之前是否有缓存,都会将新的执行结果加入到缓存中。 | ** 但与 @CachePut 不同之处的是:@CachePut 在方法执行前不去进行缓存检查,无论之前是否有缓存,都会将新的执行结果加入到缓存中。 | ||
* 需要注意的是,不要在一个方法上同时使用 @Cacheable 和 @CachePut。 | |||
支持的属性: | |||
# '''value''' | # '''value''' | ||
# '''key''' | # '''key''' | ||
# '''condition''' | # '''condition''' | ||
# '''unless''' | |||
# '''sync''' | |||
# '''keyGenerator''' | |||
# '''cacheManager''' | |||
# '''cacheResolver''' | |||
=== @CacheEvict === | === @CacheEvict === | ||
第213行: | 第280行: | ||
支持的属性: | |||
# '''value''' | # '''value''' | ||
# '''key''' | # '''key''' | ||
# '''condition''' | # '''condition''' | ||
# '''allEntrie'''属性:表示是否清除缓存中的所有 Key 键。(boolean 类型) | # '''unless''' | ||
# '''sync''' | |||
# '''keyGenerator''' | |||
# '''cacheManager''' | |||
# '''cacheResolver''' | |||
# '''allEntrie''' 属性:表示是否清除缓存中的所有 Key 键。(boolean 类型) | |||
## false:(默认)表示不需要清除全部。 | ## false:(默认)表示不需要清除全部。 | ||
## true:表示清空 value 名称属性所指向的 Cache 中所有的缓存。 | ## true:表示清空 value 名称属性所指向的 Cache 中所有的缓存。 | ||
##* 这时候,所配置的 key 属性值已经没有意义,将被忽略。 | ##* 这时候,所配置的 key 属性值已经没有意义,将被忽略。 | ||
##* 用于需要全部清空某个 Cache 的场景,这比一个一个清除 Key 键,效率更高。 | ##* 用于需要全部清空某个 Cache 的场景,这比一个一个清除 Key 键,效率更高。 | ||
# '''beforeInvocation'''属性:表示是否在方法执行前操作缓存。(boolean 类型) | # '''beforeInvocation''' 属性:表示是否在方法执行前操作缓存。(boolean 类型) | ||
## false:(默认)在对应方法成功执行之后,再触发清除操作; | ## false:(默认)在对应方法成功执行之后,再触发清除操作; | ||
##* 如果方法执行过程中,有异常抛出,或者由于其他的原因,导致线程终止,就不会触发清除操作。所以,通过设置为 true 属性来确保清理。 | ##* 如果方法执行过程中,有异常抛出,或者由于其他的原因,导致线程终止,就不会触发清除操作。所以,通过设置为 true 属性来确保清理。 | ||
第240行: | 第312行: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== @Caching === | === @Caching === | ||
第247行: | 第320行: | ||
@Caching 的组合能力,主要通过三个属性完成: | @Caching 的组合能力,主要通过三个属性完成: | ||
# '''put | # '''put''':指定一个或者多个 '''@CachePut''' 注解的组合,用于设置一个或多个 key 的缓存。 | ||
#* 如果指定多个 @CachePut 注解,则直接使用数组的形式。 | #* 如果指定多个 @CachePut 注解,则直接使用数组的形式。 | ||
#*:(即使用花括号,将多个 @CachePut 注解包围起来。) | #*:(即使用花括号,将多个 @CachePut 注解包围起来。) | ||
# '''cacheable | # '''cacheable''':指定一个或者多个 '''@Cacheable''' 注解的组合,用于查询一个或多个 key 的缓存,如果没有,则按照条件将结果加入缓存。 | ||
#* 如果指定多个 @Cacheable 注解,则直接使用数组的形式。 | #* 如果指定多个 @Cacheable 注解,则直接使用数组的形式。 | ||
# '''evict | # '''evict''':指定一个或者多个 '''@CacheEvict''' 注解的组合,用于删除一个或多个 key 的缓存。 | ||
#* 如果指定多个 @CacheEvict 注解,则直接使用数组的形式。 | #* 如果指定多个 @CacheEvict 注解,则直接使用数组的形式。 | ||
第280行: | 第353行: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== @CacheConfig === | === @CacheConfig === | ||
@CacheConfig:用于抽取缓存的公共配置。【类级别】 | @CacheConfig:用于抽取缓存的公共配置。【类级别】 | ||
* | * 允许共享:cacheNames、KeyGenerator、CacheManager 和 CacheResolver。 | ||
*: 如:“@CacheConfig(cacheNames="user")”,代表该类下的方法均使用这个 cacheNames。 | *: 如:“@CacheConfig(cacheNames="user")”,代表该类下的方法均使用这个 cacheNames。 | ||
* 如果方法上注解使用和了 @CacheConfig 相同的属性,则以方法上的为准。 | |||
支持的属性: | |||
<syntaxhighlight lang="Java" highlight=""> | |||
@Target({ElementType.TYPE}) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Documented | |||
public @interface CacheConfig { | |||
String[] cacheNames() default {}; | |||
String keyGenerator() default ""; | |||
String cacheManager() default ""; | |||
String cacheResolver() default ""; | |||
} | |||
</syntaxhighlight> | |||
# '''cacheNames''': | |||
# '''keyGenerator''': | |||
# '''cacheManager''': | |||
# '''cacheResolver''': | |||
== 缓存注解中的 SpringEL 表达式 == | == 缓存注解中的 SpringEL 表达式 == |
2021年11月8日 (一) 05:34的版本
关于
前面讲的 Redis 缓存实现都是基于 Java 代码实现的。在 Spring 中,通过合理的添加缓存注解,也能实现和前面示例程序中一样的缓存功能。
为了方便地提供缓存能力,Spring 提供了一组缓存注解。但是,这组注解不仅仅是针对 Redis,它本质上并不是一种具体的缓存实现方案(例如:Redis、EHCache等),而是对缓存使用的统一抽象。
- 通过这组缓存注解,然后加上与具体缓存相匹配的 Spring 配置,不用编码就可以快速达到缓存的效果。
配置 spring-redis.xml
在使用 Spring 缓存注解前,首先需要配置文件中启用 Spring 对基于注解的 Cache 的支持:
- 在“spring-redis.xml”中,加上“<cache:annotationdriven/>”配置项。
- 还需要配置一个名为 CacheManager 的缓存管理器 Spring Bean。
spring-redis.xml 增加的配置项,具体如下:
<!-- 省略其他的spring-redis.xml配置,具体参见源代码 --> <!-- (redis 数据源、Spring-redis 连接池管理工厂、redis template definition、将 redisTemplate 封装成通用服务,等) --> <!-- . . . --> <!--启用缓存注解功能,这个是必须的,否则注解不会生效 --> <cache:annotation-driven/> <!--自定义 redis 工具类,在需要缓存的地方注入此类 --> <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"> <constructor-arg ref="redisTemplate"/> <constructor-arg name="cacheNames"> <set> <!--声明 userCache--> <value>userCache</value> </set> </constructor-arg> </bean>
<cache:annotationdriven/> 的属性
不同的 spring-data-redis 版本,构造函数不同,这里使用的版本是 1.4.3。 对于 2.0 版本,在配置上发生了一些变化,但是原理是大致相同的。
- cache-manager 属性:用来指定所需要用到的缓存管理器(CacheManager)的 Spring Bean 的名称。【使用“<cache:annotation-driven/>”必须的属性】
- 如果不进行特别设置,默认的名称是 CacheManager。
- 设置的这个 Bean,要求实现 CacheManager 接口——CacheManager 接口是 Spring 定义的一个用来管理 Cache 缓存的通用接口。对应于不同的缓存,需要使用不同的 CacheManager 实现。
- Spring 自身已经提供了一种 CacheManager 的实现,是基于 Java API 的 ConcurrentMap 简单的内存 Key-Value 缓存实现。
- 但是,这里需要使用的缓存是 Redis,所以使用 spring-data-redis 包中的 RedisCacheManager 实现。
- 在配置 RedisCacheManager 缓存管理器 Bean 时,需要配置两个构造参数:(如上示例)
- redisTemplate:模板 Bean。
- cacheNames:缓存名称。【???】
- 在 Redis 中其实际上即为命名空间,在 Redis 中体现为 key 的前缀“<cacheName>::”。【默认使用“::”作为命名空间的分隔符(即 )】
- 系统可以配置多个 cacheName 用以区分不同业务的 key 的存储位置(命名空间)。
- mode 属性:可选值有 proxy 和 aspectj。
- “proxy”模式:【默认】
- 只有当有缓存注解的方法被对象外部的方法调用时,Spring Cache 才会发生作用(反过来说,如果一个缓存方法,被其所在对象的内部方法调用时,Spring Cache 是不会发生作用的);
- 只有加在 public 类型方法上的 @Cacheable 等注解,才会让 Spring Cache 发生作用。
- “aspectj”模式:
- 只有注解方法被内部调用,缓存才会生效;
- 非 public 类型的方法上,也可以使用 Spring Cache 注解。
- “proxy”模式:【默认】
- proxy-target-class 属性:设置代理类的创建机制,有两个值:
- 值为“true”:
- 表示使用 CGLib 创建代理类;
- @Cacheable 和 @CacheInvalidate 等注解,必须标记在具体类(Concrete Class)上,不能标记在接口上,否则不会发生作用。
- 值为“false”:【默认】
- 表示使用 JDK 的动态代理机制创建代理类。
- @Cacheable 和 @CacheInvalidate 等注解,可以标记在接口上,也能发挥作用。
- 值为“true”:
1、JDK 的动态代理是利用反射机制生成一个实现代理接口的匿名类(Class-based Proxies),在调用具体方法前,通过调用 InvokeHandler 来调用实际的代理方法。 2、而使用 CGLib 创建代理类,则不同。CGLib 底层采用 ASM 开源 .class 字节码生成框架,生成字节码级别的代理类(Interface-based Proxies)。 对比来说,在实际的运行时,CGLib代理类比使用Java反射代理类的效率要高。【参见:动态代理、CGLIB 与 切面编程】
使用 RedisTemplate 模板 API 完成 CRUD 的实践案例
简单介绍一下Spring的三个缓存注解:@CachePut、@CacheEvict、@Cacheable,通常都加在方法的前面,大致的作用如下:
- @CachePut:作用是设置缓存。
- 先执行方法,并将执行结果缓存起来。
- @Cacheable:作用更多是查询缓存。
- 首先检查注解中的 Key 键是否在缓存中,如果是,则返回 Key 的缓存值,不再执行方法;否则,执行方法并将方法结果缓存起来。
- (从后半部分来看,@Cacheable 也具备 @CachePut 的能力)
- @CacheEvict:作用是删除缓存。
- 在执行方法前,删除缓存。
示例:
- 实现一个带缓存功能的用户操作类 UserServiceImplWithAnno(UserService 的实现类,其功能和前面介绍的 UserServiceImplWithTemplate 一样):
package com.crazymakercircle.redis.springJedis; import com.crazymakercircle.im.common.bean.User; import com.crazymakercircle.util.Logger; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service @CacheConfig(cacheNames = "userCache") public class UserServiceImplWithAnno implements UserService { public static final String USER_UID_PREFIX = "'userCache:'+"; /** * CRUD 的创建/更新 * @param user 用户 */ @CachePut(key = USER_UID_PREFIX + "T(String).valueOf(#user.uid)") @Override public User saveUser(final User user) { // 保存到数据库 ... Logger.info("user : save to redis"); return user; } /** * CRUD 的查询 * @param id id * @return 用户 */ @Cacheable(key = USER_UID_PREFIX + "T(String).valueOf(#id)") @Override public User getUser(final long id) { // 从数据库中加载 User user = ...; Logger.info("user : is null"); return user; } /** * CRUD 的删除 * @param id id */ @CacheEvict(key = USER_UID_PREFIX + "T(String).valueOf(#id)") @Override public void deleteUser(long id) { // 从数据库中删除 ... Logger.info("delete User:", id); } }
如上:在 UserServiceImplWithAnno 类中没有出现任何的缓存操作 API,但是其缓存功能和前面的 UserServiceImplWithTemplate 类使用 RedisTemplate 模板实现的缓存功能,是一模一样的。
使用缓存注解,能较大地【减少代码量】,还能方便地【在不同的缓存服务之间实现切换】。
注解详解
Spring 框架自身并没有实现缓存解决方案,但是从 3.1 开始定义了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口,提供对缓存功能的声明,能够与多种流行的缓存实现集成。 1、Cache 接口为缓存的组件规范定义,包含缓存的各种操作集合; Cache 接口下 Spring 提供了各种 xxxCache 的实现,如:RedisCache、EhCacheCache、ConcurrentMapCache 等; 2、CacheManager 接口为缓存管理器规范,简单来说就是用于存放 cache。 Spring 默认也提供了一些列管理器的实现。
Spring 缓存抽象提供了 5 个注解用来声明缓存规则:
- @CachePut:执行方法,并缓存结果。
- @Cacheable:能够根据方法的请求参数对其结果进行缓存,多用于查询。
- @CacheEvict:清空缓存。
- @Caching:能够同时应用多个缓存注解功能。
- @CacheConfig:用于抽取缓存的公共配置。【仅类级别】
- 以上 5 个注解除了 @CacheConfig 注解是类级别的注解,其余 4 个注解在“类”和“方法”上均可以使用:
- 作用在类上:表示对该类下所有方法生效;(但用得较少)
- 作用在方法上:只对该方法生效;且只能用于 public 修饰的符方法,protected 或者 private 修饰的方法不适用(和配置项的“mode 属性”有关???)。
常用属性说明:
- value 属性:指定 Cache 缓存的名称。
- value 值表示当前 Key 键被缓存在哪个 Cache 上(相当于缓存 Key 所属的命名空间),对应于 Spring 配置文件中 CacheManager 缓存管理器的 cacheNames 属性中配置的某个 Cache 名称;
- 可以设置多个 Cache:配置 value 值为一个数组。(如:“value={userCache,otherCache1,otherCache2}”)
- cacheNames 为 value 的别名(Spring 4 新增)。
- key 属性:指定 Redis 的 Key 的值。
- 当没有指定该属性时,Spring 将使用默认策略(SimpleKeyGenerator)生成 Key 键:
- 如果方法没有给出参数,则返回 SimpleKey.EMPTY;【即:“key = new SimpleKey()”】
- 如果方法只给出一个参数,则返回该参数的值;【即:“key = 参数的值”】
- 如果方法给出了更多的参数,则返回包含所有参数的 SimpleKey;【即:“key = new SimpleKey(params)”】
- 当使用默认策略时,相关的参数需要有有效的“hashCode()”和“equals()”方法。
- 该属性支持 SpringEL 表达式。
- 当没有指定该属性时,Spring 将使用默认策略(SimpleKeyGenerator)生成 Key 键:
- condition 属性:指定缓存的条件“什么情况缓存”。
- 当没有指定该属性时,表示将缓存所有的结果;
- 该属性支持 SpringEL 表达式:当表达式的值为 true 时,表示进行缓存处理;否则不进行缓存处理。
- unless 属性:指定缓存的条件“什么情况不缓存”。
- 需使用 SpringEL 表达式;
- 不同于 condition 属性,该条件是在函数被调用之后才做判断的,所以它可以通过对 result 进行判断。
- sync 属性:是否使用同步模式。
- 在多线程环境中,可能会出现相同的参数的请求并发调用方法的操作,默认情况下,spring cache 不会锁定任何东西,相同的值可能会被计算几次,这就违背了缓存的目的。对于这些特殊情况,可以使用 sync 属性。
- 若设置为 true:则只有一个线程在处于计算,而其他线程则被阻塞,直到在缓存中更新条目为止。
- keyGenerator 属性:指定 key 生成器。
- 该属性与 key 属性是互斥的;
- 自定义的 key 生成器需要实现 org.springframework.cache.interceptor.KeyGenerator 接口,并使用该参数来指定:
@Configuration public class MyCacheConfig { // 省略其他配置项 . . . // 自定义 keyGenerator @Bean("myKeyGenerator") public KeyGenerator keyGenerator(){ return new KeyGenerator(){ @Override public Object generate(Object target, Method method, Object... params) { return method.getName()+"["+ Arrays.asList(params).toString()+"]"; } }; } }
- cacheManager 属性:用于指定使用哪个缓存管理器。
- 只有当配置有多个缓存管理器时才需要使用。
- cacheResolver 属性:指定使用的缓存解析器。
- 需通过 org.springframework.cache.interceptor.CacheResolver 接口来实现自己的缓存解析器,并用该参数指定。
- 需通过 org.springframework.cache.interceptor.CacheResolver 接口来实现自己的缓存解析器,并用该参数指定。
@CachePut
@CachePut:用于增加/更新缓存,每次执行方法后,会将结果存入指定缓存的 Key 键上。
支持的属性:
- value
- key
- condition
- unless
- sync
- keyGenerator
- cacheManager
- cacheResolver
Redis 的缓存都是“键-值对”(Key-Value Pair): 1、Redis 缓存的 Key 键即为 @CachePut 注解配置的 key 属性值,一般是一个字符串,或者是结果为字符串的一个 SpEL(SpringEL) 表达式。 2、Redis 缓存的 Value 值就是方法的返回结果经过序列化后所产生的序列化数据。
示例:只有当 user 的 id 大于 1000 时,才会进行缓存,缓存到“userCache”中:
@CachePut(value = "userCache", key = "T(String).valueOf(#user.uid)", condition = "#user.uid>1000") public User cacheUserWithCondition(final User user) { // 保存到数据库 . . . // 返回值将保存到缓存 Logger.info("user : save to redis"); return user; }
@Cacheable
@Cacheable:用于查询(更新)缓存,只有当 key 在缓存中不存在的情况下才执行方法(并更新缓存)。
- 与 @CachePut 注解一样,@Cacheable 也具备增加缓存的能力。
- 但与 @CachePut 不同之处的是:@CachePut 在方法执行前不去进行缓存检查,无论之前是否有缓存,都会将新的执行结果加入到缓存中。
- 需要注意的是,不要在一个方法上同时使用 @Cacheable 和 @CachePut。
支持的属性:
- value
- key
- condition
- unless
- sync
- keyGenerator
- cacheManager
- cacheResolver
@CacheEvict
@CacheEvict:用于清除缓存。
支持的属性:
- value
- key
- condition
- unless
- sync
- keyGenerator
- cacheManager
- cacheResolver
- allEntrie 属性:表示是否清除缓存中的所有 Key 键。(boolean 类型)
- false:(默认)表示不需要清除全部。
- true:表示清空 value 名称属性所指向的 Cache 中所有的缓存。
- 这时候,所配置的 key 属性值已经没有意义,将被忽略。
- 用于需要全部清空某个 Cache 的场景,这比一个一个清除 Key 键,效率更高。
- beforeInvocation 属性:表示是否在方法执行前操作缓存。(boolean 类型)
- false:(默认)在对应方法成功执行之后,再触发清除操作;
- 如果方法执行过程中,有异常抛出,或者由于其他的原因,导致线程终止,就不会触发清除操作。所以,通过设置为 true 属性来确保清理。
- true:在执行注解的方法之前完成缓存的清除工作;
- false:(默认)在对应方法成功执行之后,再触发清除操作;
示例:
- 在方法执行完成前,一次清除 Cache 名称为 userCache 中的所有的 Redis 缓存:
/** * 删除userCache名字空间的全部缓存 */ @CacheEvict(value = "userCache", allEntries = true, beforeInvocation = true) public void deleteAll() { // 其它操作 ... }
@Caching
@Caching 注解,是一个缓存处理的组合注解。
- 通过 @Caching,可以一次指定多个 Spring Cache 注解的组合。
@Caching 的组合能力,主要通过三个属性完成:
- put:指定一个或者多个 @CachePut 注解的组合,用于设置一个或多个 key 的缓存。
- 如果指定多个 @CachePut 注解,则直接使用数组的形式。
- (即使用花括号,将多个 @CachePut 注解包围起来。)
- 如果指定多个 @CachePut 注解,则直接使用数组的形式。
- cacheable:指定一个或者多个 @Cacheable 注解的组合,用于查询一个或多个 key 的缓存,如果没有,则按照条件将结果加入缓存。
- 如果指定多个 @Cacheable 注解,则直接使用数组的形式。
- evict:指定一个或者多个 @CacheEvict 注解的组合,用于删除一个或多个 key 的缓存。
- 如果指定多个 @CacheEvict 注解,则直接使用数组的形式。
在数据库中,往往需要进行外键的级联删除: 在删除一个主键时,需要将一个主键的所有级联的外键,通通都删掉。如果外键都进行了缓存,在级联删除时,则可以使用 @Caching 注解,组合多个 @CacheEvict 注解,在删除主键缓存时,删除所有的外键缓存。
示例:
- 在更新一个用户时,需要删除与用户关联的多个缓存:用户信息、地址信息、用户的消息、等等:
/** * 一个方法上,一次性加上三大类cache处理 */ @Caching(cacheable = @Cacheable(key = "'userCache:'+ #uid"), put = @CachePut(key = "'userCache:'+ #uid"), evict = { @CacheEvict(key = "'userCache:'+ #uid"), @CacheEvict(key = "'addressCache:'+ #uid"), @CacheEvict(key = "'messageCache:'+ #uid") } ) public User updateRef(String uid) { // 业务逻辑 ... return null; }
@CacheConfig
@CacheConfig:用于抽取缓存的公共配置。【类级别】
- 允许共享:cacheNames、KeyGenerator、CacheManager 和 CacheResolver。
- 如:“@CacheConfig(cacheNames="user")”,代表该类下的方法均使用这个 cacheNames。
- 如果方法上注解使用和了 @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: