一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
前言
如果要使用quarkus 的native image 本地编译,使用spring等的redisclient 都可能导致一些难以解决的问题。那么取而代之的就是quarkus-redis-client
了,本文将简单的讨论一下如何使用quarkus-redis-client
作为缓存的方法。在这篇文章中,我们将实现redis客户端的 GET
, SET
, DEL
和 KEYS
等简单操作的方法,并且给我们上文的天气预报响应式方法加上缓存。
配置和依赖
quarkus有关的部分依赖都已经在前文中有展示。这里在maven中先引入quarkus-redis-client
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
复制代码
然后在配置的properties中加入 redis的配置
quarkus.redis.hosts=redis://localhost:6379
quarkus.redis.database=0
quarkus.redis.timeout=10s
复制代码
然后编写redisService,使得使用更加接近传统的redis 客户端服务。
@ApplicationScoped
public class RedisClientService {
@Inject
RedisClient redisClient;
@Inject
ReactiveRedisClient reactiveRedisClient;
public String get(String key) {
Response response = redisClient.get(key);
return response == null ? null : response.toString();
}
void set(String key, String value) {
redisClient.set(Arrays.asList(key, value.toString()));
}
Uni<JsonArray> result =
// Step 1 - 获得key
reactiveRedisClient.keys("*")
.onItem().transformToMulti(keys -> Multi.createFrom().iterable(keys))
.onItem().castTo(String.class)
// Step 2 - 检索相关对象对于每一个key
.onItem().transformToUniAndMerge(key -> reactiveRedisClient.hgetall(key))
// Step 3 and 4 - 生成包含所有对象的JsonArray
.collect().in(JsonArray::new, JsonArray::add);
复制代码
在Quarkus的redis client中存在两个类型的客户端,一个是RedisClient
,一个是ReactiveRedisClient
。RedisClient
支持传统型的增删改查,ReactiveRedisClient
是Quarkus编写的更适合响应式编程的方法。 举个例子,如果想要实现一种redis使用方式:
1.从Redis获取所有密钥
2.对于每个键->检索相关对象
3.将此对象添加到JsonArray
4.生成包含所有对象的JsonArray
复制代码
如何不增加大量的业务代码就能简单有效的实现这样的效果。直接通过ReactiveRedisClient
返回的Uni
就可以:
Uni<JsonArray> result =
// Step 1 - 获得key
reactiveRedisClient.keys("*")
.onItem().transformToMulti(keys -> Multi.createFrom().iterable(keys))
.onItem().castTo(String.class)
// Step 2 - 检索相关对象对于每一个key
.onItem().transformToUniAndMerge(key -> redis.hgetall(key))
// Step 3 and 4 - 生成包含所有对象的JsonArray
.collect().in(() -> new JsonArray(), (arr, obj) -> arr.add(obj));
复制代码
Quarkus中的响应式代码设计让很多业务逻辑和计算的实现大大的简化了。
这里我们使用原有的代码逻辑获取天气,并且将天气缓存到redis的客户端中
public Uni<Weather> testCache( String name) {
Weather dto = null;
if(null!=redisClientService.get(name)){
dto= JSONObject.parseObject(redisClientService.get(name), Weather.class);
return Uni.createFrom().item(dto);
}
String code= cityService.getCode(name);
try {
dto = JSONObject.parseObject(restClient.getStream(code), Weather.class);
} catch (IOException e) {
e.printStackTrace();
}
redisClientService.set(name,JSONObject.toJSONString(dto));
return Uni.createFrom().item(dto);
}
复制代码
默认redis已经安装好了在机器上,使用brew services start redis
启动redis的服务器。
使用 $ mvn quarkus:dev
启动调试模式,第一次执行是没有缓存,直接调用网络接口
然后再次调用就快了很多倍
再简单的做个对比 同时调用150次,不同的城市,缓存和接口的速度对比,首先使用接口 :
private static String[] cityNames = new String[]{"北京", "上海", "广州", "深圳", "南京"};
private static int[] cityTimes = new int[]{50, 40, 30, 20, 10};
复制代码
调用结果如下
总计10685ms
使用缓存的版本:
总计 1478ms
考虑到各种因素,缓存大概能加速整个查询的过程10倍。