Redis-JetCache缓存集成

官网:https://github.com/alibaba/jetcache

本地项目集成:https://gitee.com/xushuyi1002/micro2.0/tree/master/jetcache

一、介绍

JetCache是一个基于Java的缓存系统封装,提供统一的API和注解来简化缓存的使用。JetCache提供了比SpingCache更加强大的注解,可以原生的支持TTL、两级缓存、分布式自动刷新,还提供了Cache接口用于手工缓存操作。当前有四个实现,RedisCache、TairCache,CaffeineCache(in memory)和一个简易的LinkedHashMapCache(in memory),要添加新的实现也是非常简单的。

全部特性:

  1. 通过统一的API访问Cache系统
  2. 通过注解实现声明式的方法缓存,支持TTL和两级缓存
  3. 通过注解创建并配置Cache实例
  4. 针对所有Cache实例和方法缓存的自动统计
  5. Key的生成策略和Value的序列化策略是可以配置的
  6. 分布式缓存自动刷新,分布式锁 (2.2+)
  7. 异步Cache API (2.2+,使用Redis的lettuce客户端时)
  8. Spring Boot支持

二、要求

JetCache需要JDK1.8、Spring Framework4.0.8以上版本。Spring Boot为可选,需要1.1.9以上版本。如果不使用注解(仅使用jetcache-core),Spring Framework也是可选的,此时使用方式与Guava/Caffeine cache类似。

三、缓存使用

(一)缓存实例

(二)方法缓存

JetCache方法缓存和SpringCache比较类似,它原生提供了TTL支持,以保证最终一致,并且支持二级缓存。JetCache2.4以后支持基于注解的缓存更新和删除。在spring环境下,使用@Cached注解可以为一个方法添加缓存,@CacheUpdate用于更新缓存,@CacheInvalidate用于移除缓存元素。注解可以加在接口上也可以加在类上,加注解的类必须是一个spring bean。

1 缓存注解

1.1 Cached

一种在方法上增加缓存的注解,可以实现在接口和类方法上。我这边倾向于实现接口上的方式,具体用例:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", condition = "#userGoodsCacheDTO.userId != null and #userGoodsCacheDTO.userId > 0", postCondition = "result != null", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

1.2 CacheInvalidate

一种在方法删除缓存的注解,可以实现在接口和类方法上。我这边倾向于实现接口上的方式,具体用例:

@CacheInvalidate(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userId")
void deleteUserGoods2(Long userId);

1.3 CacheUpdate

一种在方法更新缓存的注解,可以实现在接口和类方法上。我这边介绍下接口上的实现方式,具体用例:

@CacheUpdate(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", value = "#userGoodsCacheDTO")
void updateUserGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

1.4 CacheRefresh

一种在方法自动刷新缓存的注解,可以实现在接口和类方法上。我这边介绍下接口上的实现方式,具体用例:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", condition = "#userGoodsCacheDTO.userId != null and #userGoodsCacheDTO.userId > 0", postCondition = "result != null", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CacheRefresh(refresh = 10, stopRefreshAfterLastAccess = 30)
@CachePenetrationProtect
Object refreshUserGoods3(Long userId);

refresh:刷新间隔,默认时间单位:秒

stopRefreshAfterLastAccess:指定该key多长时间没有访问就停止刷新,如果不指定会一直刷新,默认时间单位:秒

refreshLockTimeout:类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间,默认为60秒

1.5 CachePenetrationProtect

当缓存访问未命中的情况下,对并发进行的加载行为进行保护。 当前版本实现的是单JVM内的保护,即同一个JVM中同一个key只有一个线程去加载,其它线程等待结果。

所以@Cached 结合 @CachePenetrationProtect 一起使用。

2 缓存属性

2.1 area

默认值

说明

“default”

如果在配置中配置了多个缓存area,在这里指定使用哪个area

例子:无

2.2 name

默认值

说明

未定义

指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。

例子:

public static final String USER_GOODS_CACHE = "JET_CACHE:USER_GOODS:USER_GOODS_CACHE:";

@Cached(name = JetCacheConstant.USER_GOODS_CACHE)
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

2.3 key

默认值

说明

未定义

使用SpEL指定key,如果没有指定会根据所有参数自动生成。

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userId")

@CachePenetrationProtect
Object userGoods2(Long userId);

注:如果入参为实体对象,则:key = “#对象.属性

如果是多个key值拼接,方式:key = “#goodsId + ‘_’ + #forceGetAllLabel”

2.4 expire

默认值

说明

未定义

超时时间。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为无穷大

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", expire = 3600)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

注:如果没有指定时间单位timeUnit则默认为 3600 秒

2.5 timeUnit

默认值

说明

TimeUnit.SECONDS

指定expire的单位

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", expire = 3600, timeUnit = TimeUnit.MINUTES)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

2.6 cacheType

默认值

说明

CacheType.REMOTE

缓存的类型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", expire = 3600, timeUnit = TimeUnit.MINUTES, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

2.7 localLimit

默认值

说明

未定义

如果cacheType为LOCAL或BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为100

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", expire = 3600, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

2.8 localExpire

默认值

说明

未定义

仅当cacheType为BOTH时适用,为内存中的Cache指定一个不一样的超时时间,通常应该小于expire

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

注:本地缓存时间为什么要比远程缓存时间小,由于本地缓存使用会占用服务内存,尽量保证在热点使用,闲事尽量释放本地缓存释放服务内存资源。

2.9 serialPolicy

默认值

说明

未定义

指定远程缓存的序列化方式。可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为SerialPolicy.JAVA

采用全局配置 kryo

2.10 keyConvertor

默认值

说明

未定义

指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,当前支持KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON可以将复杂对象KEY转换成String。如果注解上没有定义,会使用全局配置。

采用全局配置 fastjson

2.11 enabled

默认值

说明

true

是否激活缓存。例如某个dao方法上加缓存注解,由于某些调用场景下不能有缓存,所以可以设置enabled为false,正常调用不会使用缓存,在需要的地方可使用CacheContext.enableCache在回调中激活缓存,缓存激活的标记在ThreadLocal上,该标记被设置后,所有enable=false的缓存都被激活

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH, enabled = false)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

2.12 cacheNullValue

默认值

说明

false

当方法返回值为null的时候是否要缓存

例子:无

2.13 condition

默认值

说明

未定义

使用SpEL指定条件,如果表达式返回true的时候才去缓存中查询

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", condition = "#userGoodsCacheDTO.userId != null and #userGoodsCacheDTO.userId > 0", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);
@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.goodsName", condition = "#userGoodsCacheDTO.goodsName != null and #userGoodsCacheDTO.goodsName != ''", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

注:userId 为 Long型;goodsName 为String型

2.14 postCondition

默认值

说明

未定义

使用SpEL指定条件,如果表达式返回true的时候才更新缓存,该评估在方法执行后进行,因此可以访问到#result

例子:

@Cached(name = JetCacheConstant.USER_GOODS_CACHE, key = "#userGoodsCacheDTO.userId", condition = "#userGoodsCacheDTO.userId != null and #userGoodsCacheDTO.userId > 0", postCondition = "result != null", expire = 3600, localExpire = 30, timeUnit = TimeUnit.MINUTES, localLimit = 500, cacheType = CacheType.BOTH)
@CachePenetrationProtect
Object userGoods2(UserGoodsCacheDTO userGoodsCacheDTO);

注:如果是Boolean判断 为true 才缓存:postCondition = “result == true”


版权声明:本文为m0_37542440原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。