Jackson2无法对proto序列化,因此导致缓存很是费劲,也没有查到优雅的解决方案。
自己研究了一下午,顺利解决,现在与大家分享。因为内网开发,搬运代码过于费劲,这里就不展示运行结果了。
代码基于proto3实现,用proto2的话仅需修改 少量代码,具体改哪自己研究
序列化器
public class ProtoSerializer extends StdScalarSerializer<GeneratedMessageV3> {
public ProtoSerializer() {
super(GeneratedMessageV3.class);
}
@Override
public void serialize(GeneratedMessageV3 generatedMessageV3, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
serialize(generatedMessageV3, jsonGenerator, serializerProvider,false);
}
public void serialize(GeneratedMessageV3 value, JsonGenerator gen, SerializerProvider provider, boolean isProperty) throws IOException {
byte[] bytes = value.toByteArray();
gen.writeStartArray();
if (!isProperty) {
//通过这个找到对应的反序列化器
gen.writeString(GeneratedMessageV3.class.getName());
}
//记录具体类型
gen.writeString(value.getClass().getName());
gen.writeBinary(bytes);
gen.writeEndArray();
}
@Override
public void serializeWithType(GeneratedMessageV3 value, JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer) throws IOException {
//对外一律以父类 GeneratedMessageV3 显示类型
WritableTypeId typeId = typeSer.typeId(value, GeneratedMessageV3.class, JsonToken.VALUE_STRING);
WritableTypeId typeIdDef = typeSer.writeTypePrefix(g,typeId);
serialize(value, g, provider, true);
typeSer.writeTypeSuffix(g, typeIdDef);
}
反序列化器
public class ProtoDeserializer extends StdScalarDeserializer {
protected ProtoDeserializer() {
super(com.google.protobuf.GeneratedMessageV3.class);
}
@Override
@SneakyThrows
public Object deserialize(JsonParser p, DeserializationContext gtxt) {
//判断是否“[”开头 是的话跳过“[”,结束时也要跳过“]”
boolean b = p.currentToken() == JsonToken.START_ARRAY;
if (b) {
p.nextToken();
}
String text = p.getText();
Class<?> aClass = Class.forName(text);
p.nextToken();
Object parseFrom = aClass.getMethod(
"parseFrom", byte[].class).invoke(null, p.getBinaryValue());
if (b) {
p.nextToken();
}
return parseFrom;
}
应用序列化器,使用springCache 的话 也只需参考以下代码改动Jackson2序列化器 部分即可
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
//将proto序列化反序列化加入到Mapper里
SimpleModule module = new SimpleModule();
module.addDeserializer(GeneratedMessageV3.class,new ProtoDeserializer());
module.addSerializer(GeneratedMessageV3.class,new ProtoSerializer());
om.registerModule(module);
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}