SpringRedis Jackson2序列化器整合 protobuf

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;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值