前言
博主所在公司大量使用了redis缓存,redis客户端用的Redisson。在Quarkus集成redis时,博主尝试使用Redisson客户端直接集成,发现,在jvm模式下运行quarkus没点问题,但是在打native image时,就报错了,尝试了很多方式都是莫名其妙的异常。最后决定采用quarkus官方的redis客户端,但是Redisson客户端数据序列化方式是特有的,不是简单的String,所以quarkus中的redis需要操作Redisson的数据,就要保持序列化方式一致,本文就是为了解决这个问题。
Quarkus版本:1.7.0.CR1
集成redis
首先你的quarkus版本一定要1.7.0.CR1版本及以上才行,因为redis的扩展包是这个版本才发布的,添加依赖:
代码语言:javascript复制 <dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
新增redis链接配置
代码语言:javascript复制quarkus.redis.hosts=127.0.0.1:6379
quarkus.redis.database=0
quarkus.redis.timeout=10s
quarkus.redis.password=sasa
复制Redisson序列化
Redisson里内置了很多的序列化方式,我们用的JsonJacksonCodec,这里将Redisson中的实现复制后,稍加改动,如下:
代码语言:javascript复制/**
* 和Redisson的序列化数据互相反序列化的编解码器
* @author keking
*/
public class JsonJacksonCodec{
public static final JsonJacksonCodec INSTANCE = new JsonJacksonCodec();
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
@JsonAutoDetect(fieldVisibility = Visibility.ANY,
getterVisibility = Visibility.PUBLIC_ONLY,
setterVisibility = Visibility.NONE,
isGetterVisibility = Visibility.NONE)
public static class ThrowableMixIn {
}
protected final ObjectMapper mapObjectMapper;
public JsonJacksonCodec() {
this(new ObjectMapper());
}
public JsonJacksonCodec(ObjectMapper mapObjectMapper) {
this.mapObjectMapper = mapObjectMapper.copy();
init(this.mapObjectMapper);
initTypeInclusion(this.mapObjectMapper);
}
protected void initTypeInclusion(ObjectMapper mapObjectMapper) {
TypeResolverBuilder<?> mapTyper = new DefaultTypeResolverBuilder(DefaultTyping.NON_FINAL) {
@Override
public boolean useForType(JavaType t) {
switch (_appliesFor) {
case NON_CONCRETE_AND_ARRAYS:
while (t.isArrayType()) {
t = t.getContentType();
}
// fall through
case OBJECT_AND_NON_CONCRETE:
return (t.getRawClass() == Object.class) || !t.isConcrete();
case NON_FINAL:
while (t.isArrayType()) {
t = t.getContentType();
}
// to fix problem with wrong long to int conversion
if (t.getRawClass() == Long.class) {
return true;
}
if (t.getRawClass() == XMLGregorianCalendar.class) {
return false;
}
return !t.isFinal(); // includes Object.class
default:
// case JAVA_LANG_OBJECT:
return t.getRawClass() == Object.class;
}
}
};
mapTyper.init(JsonTypeInfo.Id.CLASS, null);
mapTyper.inclusion(JsonTypeInfo.As.PROPERTY);
mapObjectMapper.setDefaultTyping(mapTyper);
}
protected void init(ObjectMapper objectMapper) {
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setVisibility(objectMapper.getSerializationConfig()
.getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
objectMapper.enable(Feature.WRITE_BIGDECIMAL_AS_PLAIN);
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
objectMapper.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY);
objectMapper.addMixIn(Throwable.class, ThrowableMixIn.class);
}
/**
* 解码器
* @param val
* @return
*/
public Object decoder(String val){
try {
ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
try (ByteBufOutputStream os = new ByteBufOutputStream(buf)) {
os.write(val.getBytes());
}
return mapObjectMapper.readValue((InputStream) new ByteBufInputStream(buf), Object.class);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 编码器
* @param obj
* @return
*/
public String encoder(Object obj){
ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
try {
ByteBufOutputStream os = new ByteBufOutputStream(out);
mapObjectMapper.writeValue((OutputStream) os, obj);
return os.buffer().toString(StandardCharsets.UTF_8);
} catch (IOException e) {
out.release();
}
return null;
}
}
使用
代码语言:javascript复制@Dependent
@Startup
public class Test {
@Inject
RedisClient redisClient;
@Inject
Logger logger;
void initializeApp(@Observes StartupEvent ev) {
//使用JsonJacksonCodec编解码,保持和redisson互通
JsonJacksonCodec codec = JsonJacksonCodec.INSTANCE;
Map<String, String> map = new HashMap<>();
map.put("key","666");
redisClient.set(Arrays.asList("AAAKEY", codec.encoder(map)));
String str = redisClient.get("AAAKEY").toString(StandardCharsets.UTF_8);
Map<String,String> getVal = (Map<String, String>) codec.decoder(str);
logger.info(getVal.get("key"));
}
}