jetcache-阿里多级缓存框架神器一定要掌握
文章目录
- 1. 简介
- 2. springboot集成jetcache
- 2.1 引入依赖
- 2.2 配置文件
- 2.3 高级API模式:通过CacheManager使用缓存,2.7 版本才可使用
- 2.4 (推荐)AOP模式:通过@Cached,@CacheUpdate,@CacheInvalidate注解
1. 简介
JetCache是一个基于Java的缓存系统封装,提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解,可以原生的支持TTL、两级缓存、分布式自动刷新,还提供了Cache接口用于手工缓存操作。 当前有四个实现,RedisCache、TairCache(此部分未在github开源)、CaffeineCache(in memory)和一个简易的LinkedHashMapCache(in memory),要添加新的实现也是非常简单的。
JetCache需要JDK1.8、Spring Framework4.0.8以上版本。Spring Boot为可选,需要1.1.9以上版本。如果不使用注解(仅使用jetcache-core),Spring Framework也是可选的,此时使用方式与Guava/Caffeine cache类似。
全部特性:
通过统一的API访问Cache系统
通过注解实现声明式的方法缓存,支持TTL和两级缓存
通过注解创建并配置Cache实例
针对所有Cache实例和方法缓存的自动统计
Key的生成策略和Value的序列化策略是可以配置的
分布式缓存自动刷新,分布式锁 (2.2+)
异步Cache API (2.2+,使用Redis的lettuce客户端时)
Spring Boot支持
2. springboot集成jetcache
务必根据配置文件引入相关依赖,否则会有各种报错,本文以caffeine、redis.lettuce缓存为例
2.1 引入依赖
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis-lettuce</artifactId>
<version>${jetcache.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2.2 配置文件
jetcache:
statIntervalMinutes: ${CACHE_STATS_INTERNAL:1} # 统计间隔,0表示不统计
areaInCacheName: true # jetcache-anno把cacheName作为远程缓存key前缀,为了保持远程key兼容默认值为true,但是新项目的话false更合理些。
enabled: ${JETCACHE_ENABLED:true}
local:
default:
type: caffeine # 缓存类型,本地缓存类型支持linkedhashmap、caffeine
keyConvertor: jackson
remote:
default:
type: redis.lettuce # 缓存类型:远程缓存支持tair、redis
keyConvertor: jackson # key转换器的全局配置
broadcastChannel: 'jetCache'
keyPrefix: 'jetCache'
valueEncoder: java # 序列化器的全局配置。仅remote类型的缓存需要指定,可选java和kryo
valueDecoder: java # 序列化器的全局配置。仅remote类型的缓存需要指定,可选java和kryo
defaultExpireInMillis: 60000
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
uri: 'redis://${JETCACHE_PASSWD:}@${JETCACHE_HOST:}:${JETCACHE_PORT:}/?database=${JETCACHE_DATABASE:4}'
2.3 高级API模式:通过CacheManager使用缓存,2.7 版本才可使用
@Configuration
public class JetCacheConfig {
/**
* 缓存管理器.
*/
@Resource
private CacheManager cacheManager;
/**
* 消息模版ID缓存.
*/
private Cache<String, String> msgTemplateCache;
/**
* 初始化缓存.
*/
@PostConstruct
public void init() {
// 1、一级缓存:仅使用本地缓存,切永不失效
// msgTemplateCache = cacheManager.getOrCreateCache(QuickConfig.newBuilder("cache-")
// .cacheType(CacheType.LOCAL)
// .build());
// 2、二级缓存: 使用本地缓存+redis
Duration cacheDuration = Duration.ofSeconds(2 * 60);
QuickConfig qc = QuickConfig.newBuilder("cache-")
.cacheType(CacheType.BOTH)
.syncLocal(true)
.localLimit(1000)
.localExpire(cacheDuration)
.expire(cacheDuration)
.build();
msgTemplateCache = cacheManager.getOrCreateCache(qc);
}
@Bean
public Cache<String, String> getMsgTemplateCache() {
return msgTemplateCache;
}
}
@Slf4j
@Component
public class ProjectInitDataTask implements ApplicationRunner {
/**
* 消息模版缓存.
*/
@Autowired
private Cache<String, String> msgTemplateCache;
@Override
public void run(ApplicationArguments args) {
log.info("模拟创建缓存jetcache...");
msgTemplateCache.put("msgTemplateCache1", "msgTemplateCache1");
msgTemplateCache.put("msgTemplateCache2", "msgTemplateCache2");
msgTemplateCache.put("msgTemplateCache3", "msgTemplateCache3");
log.info("模拟创建缓存jetcache完成...");
}
}
2.4 (推荐)AOP模式:通过@Cached,@CacheUpdate,@CacheInvalidate注解
@GetMapping("getRemote")
@Cached(name="userCache:", key = "#id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.REMOTE)
public User getRemote(Long id){
User user = new User();
user.setId(id);
user.setName("用户remote"+id);
user.setAge(23);
user.setSex(1);
System.out.println("第一次获取数据,未走缓存:"+id);
return user;
}
@GetMapping("getLocal")
@Cached(name="userCache:", key = "#id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.LOCAL)
public User getLocal(Long id){
// 直接新建用户,模拟从数据库获取数据
User user = new User();
user.setId(id);
user.setName("用户local"+id);
user.setAge(23);
user.setSex(1);
System.out.println("第一次获取数据,未走缓存:"+id);
return user;
}
@GetMapping("getBoth")
@Cached(name="userCache:", key = "#id", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.BOTH)
public User getBoth(Long id){
// 直接新建用户,模拟从数据库获取数据
User user = new User();
user.setId(id);
user.setName("用户both"+id);
user.setAge(23);
user.setSex(1);
System.out.println("第一次获取数据,未走缓存:"+id);
return user;
}
@PostMapping("updateUser")
@CacheUpdate(name = "userCache:", key = "#user.id", value = "#user")
public Boolean updateUser(@RequestBody User user){
// TODO 更新数据库
return true;
}
@PostMapping("deleteUser")
@CacheInvalidate(name = "userCache:", key = "#id")
public Boolean deleteUser(Long id){
// TODO 从数据库删除
return true;
}