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
    评论
要在Java中获取Redis中的Protobuf序列化数据,你需要使用RedisJava客户端库和ProtobufJava库。以下是一个简单的示例代码,显示如何将Protobuf对象序列化并存储到Redis中,并从Redis中获取并反序列化Protobuf对象。 首先,确保你已经添加了RedisProtobuf的相关依赖。 ```java import redis.clients.jedis.Jedis; import com.google.protobuf.InvalidProtocolBufferException; public class RedisProtobufExample { public static void main(String[] args) { // 创建一个Redis连接 Jedis jedis = new Jedis("localhost"); // 创建一个Protobuf对象 YourProtobufMessage message = YourProtobufMessage.newBuilder() .setId(1) .setName("John Doe") .setEmail("johndoe@example.com") .build(); // 将Protobuf对象序列化为字节数组 byte[] serializedMessage = message.toByteArray(); // 存储序列化的字节数组到Redis中 jedis.set("protobufData", serializedMessage); // 从Redis中获取序列化的字节数组 byte[] retrievedData = jedis.get("protobufData"); try { // 将字节数组反序列化Protobuf对象 YourProtobufMessage retrievedMessage = YourProtobufMessage.parseFrom(retrievedData); System.out.println(retrievedMessage); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } // 关闭Redis连接 jedis.close(); } } ``` 在上面的示例代码中,你需要替换`YourProtobufMessage`为你实际使用的Protobuf消息类型。你还需要根据你的Redis配置修改Redis连接的相关参数。 这是一个简单的例子,你可以根据自己的需求进行扩展和修改。希望对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值