使用JetCache构建多级缓存

多级缓存使用:

  1. 本地缓存使用Caffeine
  2. 分布式缓存使用Redis(Redisson也可以)

JetCache简介:


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

全部特性:

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

要求

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

可依赖的jar包

  • jetcache-anno-api:定义jetcache的注解和常量,不传递依赖。如果你想把Cached注解加到接口上,又不希望你的接口jar传递太多依赖,可以让接口jar依赖jetcache-anno-api。
  • jetcache-core:核心api,完全通过编程来配置操作Cache,不依赖Spring。两个内存中的缓存实现LinkedHashMapCacheCaffeineCache也由它提供。
  • jetcache-anno:基于Spring提供@Cached和@CreateCache注解支持。
  • jetcache-redis:使用jedis提供Redis支持。
  • jetcache-redis-lettuce(需要JetCache2.3以上版本):使用lettuce提供Redis支持,实现了JetCache异步访问缓存的的接口。
  • jetcache-starter-redis:Spring Boot方式的Starter,基于Jedis。
  • jetcache-starter-redis-lettuce(需要JetCache2.3以上版本):Spring Boot方式的Starter,基于Lettuce。

创建缓存实例:

依赖:这里使用了jedis客户端连接redis,也可以使用lettuce客户端

xml
复制代码
<dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-starter-redis</artifactId> <version>${jetcache.latest.version}</version> </dependency>

使用lettuce的方式访问Redis:

xml
复制代码
<!-- 使用Lettuce访问Redis --> <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-redis-lettuce</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>com.alicp.jetcache</groupId> <artifactId>jetcache-starter-redis-lettuce</artifactId> <version>2.7.5</version> </dependency>

yml文件配置:

yml
复制代码
server: port: 8080 spring: application: name: JetCache redis: host: localhost port: 6379 password: 123456 lettuce: pool: min-idle: 0 # 连接池中的最小空闲连接 max-idle: 10 # 连接池中的最大空闲连接 max-active: 20 # 连接池的最大连接数 max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制) jetcache: statIntervalMinutes: 15 areaInCacheName: false local: default: type: caffeine keyConvertor: fastjson2 remote: default: type: redis keyConvertor: fastjson2 broadcastChannel: ${spring.application.name} keyPrefix: ${spring.application.name} valueEncoder: java valueDecoder: java defaultExpireInMillis: 5000 poolConfig: minIdle: 5 maxIdle: 20 maxTotal: 50 host: 127.0.0.1 port: 6379 password: 123456

注意:

如果valueEncoder和valueDecoder配置成了java,那么初始化到缓存中的数据就是以二进制形式存储的

image.png

改进措施:

在初始化的时候,设置valueEncoder和valueDecoder,yml文件中的这两个配置就可以去掉了 .valueEncoder(Fastjson2ValueEncoder.INSTANCE) .valueDecoder(Fastjson2ValueDecoder.INSTANCE)

java
复制代码
@Autowired private CacheManager cacheManager; private Cache<String, User> userCache; @PostConstruct public void init() { QuickConfig quickConfig = QuickConfig.newBuilder(":userCache:") // 缓存的key .expire(Duration.ofHours(2)) // 设置缓存的过期时间 .cacheType(CacheType.BOTH) // 缓存的类型 BOTH 表示本地缓存和分布式缓存都创建 .localLimit(1000) // 本地缓存元素的个数限制,只对CacheType.Local和CacheType.BOTH 有效(因为只有这两个有本地缓存) .syncLocal(true) // 两级缓存的情况下,缓存更新时发消息让其他JVM实例中的缓存失效,需要配置broadcastChannel才生效 .valueEncoder(Fastjson2ValueEncoder.INSTANCE) //使用fastjosn2进行序列化编码 .valueDecoder(Fastjson2ValueDecoder.INSTANCE) //使用fastjosn2进行序列化解码 .build(); userCache = cacheManager.getOrCreateCache(quickConfig); }
效果:
image.png

再次优化:使用自定义序列化的方式解决乱码

自定义编码器:

java
复制代码
package com.cache; import com.alicp.jetcache.support.AbstractValueEncoder; import com.alicp.jetcache.support.CacheEncodeException; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONWriter; public class CustomFastjson2ValueEncoder extends AbstractValueEncoder { public static final CustomFastjson2ValueEncoder INSTANCE = new CustomFastjson2ValueEncoder(true); // 指定序列化特性 private static final JSONWriter.Feature[] features = { JSONWriter.Feature.WriteClassName, // 写入类名(可选,按需开启) //JSONWriter.Feature.DisableCircularReferenceDetect // 禁用循环引用检测 }; public CustomFastjson2ValueEncoder(boolean useIdentityNumber) { super(useIdentityNumber); } @Override public byte[] apply(Object value) { try { // 使用 UTF-8 编码序列化 return JSON.toJSONBytes(value, features); } catch (Exception e) { throw new CacheEncodeException("Fastjson2 Encode Error: " + e.getMessage(), e); } } }

自定义解码器:

java
复制代码
package com.cache; import com.alicp.jetcache.support.AbstractValueDecoder; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONReader; import com.alicp.jetcache.support.CacheEncodeException; public class CustomFastjson2ValueDecoder extends AbstractValueDecoder { public static final CustomFastjson2ValueDecoder INSTANCE = new CustomFastjson2ValueDecoder(true); // 指定反序列化特性 private static final JSONReader.Feature[] features = { //JSONReader.Feature.SupportAutoType, // 启用 AutoType(需白名单配置) JSONReader.Feature.IgnoreAutoTypeNotMatch }; public CustomFastjson2ValueDecoder(boolean useIdentityNumber) { super(useIdentityNumber); } @Override public Object doApply(byte[] bytes) { try { return JSON.parseObject(bytes, Object.class, features); } catch (Exception e) { throw new CacheEncodeException("Fastjson2 Decode Error: " + e.getMessage(), e); } } }
效果:
image.png
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
航
下载 APP