配置RedissonClient

@Bean
public RedissonClient redissonClient() {
    Config config = new Config();
    // 单节点模式
    SingleServerConfig singleServerConfig = config.useSingleServer();
    singleServerConfig.setAddress("redis://127.0.0.1:6379");
    singleServerConfig.setPassword("");
    // 使用json序列化方式
    Codec codec = new JsonJacksonCodec();
    config.setCodec(codec);
    RedissonClient redissonClient = Redisson.create(config);
    return redissonClient;
}

除上方配置的单机模式,其它模式配置:



redistemplate序列化 redisson 序列化_redis


数据序列化

Redisson的对象编码类是用于将对象进行序列化和反序列化,以实现对该对象在Redis里的读取和存储。Redisson提供了以下几种的对象编码应用,以供大家选择:


编码类名称

说明

org.redisson.codec.JsonJacksonCodec

Jackson JSON 编码 默认编码

org.redisson.codec.AvroJacksonCodec

Avro 一个二进制的JSON编码

org.redisson.codec.SmileJacksonCodec

Smile 另一个二进制的JSON编码

org.redisson.codec.CborJacksonCodec

CBOR 又一个二进制的JSON编码

org.redisson.codec.MsgPackJacksonCodec

MsgPack 再来一个二进制的JSON编码


org.redisson.codec.IonJacksonCodec

Amazon Ion 亚马逊的Ion编码,格式与JSON类似

org.redisson.codec.KryoCodec

Kryo 二进制对象序列化编码

org.redisson.codec.SerializationCodec

JDK序列化编码

org.redisson.codec.FstCodec

FST 10倍于JDK序列化性能而且100%兼容的编码

org.redisson.codec.LZ4Codec

LZ4 压缩型序列化对象编码

org.redisson.codec.SnappyCodec

Snappy 另一个压缩型序列化对象编码

org.redisson.client.codec.JsonJacksonMapCodec

基于Jackson的映射类使用的编码。可用于避免序列化类的信息,以及用于解决使用byte[]遇到的问题。

org.redisson.client.codec.StringCodec

纯字符串编码(无转换)

org.redisson.client.codec.LongCodec

纯整长型数字编码(无转换)

org.redisson.client.codec.ByteArrayCodec

字节数组编码

org.redisson.codec.CompositeCodec

用来组合多种不同编码在一起


自定义序列化

需求背景:

项目之前使用的RestTemplate api,RestTemplate的序列化使用的RedisSerializer接口,使用的实现类Jackson2JsonRedisSerializer。

现在改为使用RedissonClient,RedissonClient的序列化使用的Codec接口,默认实现类JsonJacksonCodec。

2种实现类序列化方式不同,而生产环境数据迁移有风险,所以需实现Codec接口,自定义RedissonClient序列化方式,替换Redisson的序列化对象JsonJacksonCodec,兼容旧数据。

目的:

兼容原有RedisTemplate Jackson2JsonRedisSerializer对象序列化数据。

分析:

RedisTemplate初始化代码:

protected RedisTemplate<String, Object> buildRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, 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;
    }

JsonJacksonCodec构造器初始化源码:

public JsonJacksonCodec() {
        this(new ObjectMapper());
    }

跟踪发现底层初始化时,默认给ObjectMapper设置了一些参数:

init(this.mapObjectMapper);

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

就是这些ObjectMapper的初始化参数导致对象序列化数据不兼容,所以自定义Codec,和原来ObjectMapper的初始化保持一致即可!

实现:

自定义Codec实现类:RedissonCodec

/**
 * 替换Redisson的序列化对象JsonJacksonCodec,兼容原有RedisTemplate的对象序列化。
 *
 * @author yangzihe
 * @date 2022/12/13
 */
public class RedissonCodec extends BaseCodec {

    protected final ObjectMapper mapObjectMapper;

    /**
     * @see JsonJacksonCodec
     */
    private final Encoder encoder = new Encoder() {
        @Override
        public ByteBuf encode(Object in) throws IOException {
            ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
            try {
                ByteBufOutputStream os = new ByteBufOutputStream(out);
                mapObjectMapper.writeValue((OutputStream) os, in);
                return os.buffer();
            } catch (IOException e) {
                out.release();
                throw e;
            } catch (Exception e) {
                out.release();
                throw new IOException(e);
            }
        }
    };

    private final Decoder<Object> decoder = new Decoder<Object>() {
        @Override
        public Object decode(ByteBuf buf, State state) throws IOException {
            return mapObjectMapper.readValue((InputStream) new ByteBufInputStream(buf), Object.class);
        }
    };

    public RedissonCodec(ObjectMapper mapObjectMapper) {
        this(mapObjectMapper, true);
    }

    public RedissonCodec(ObjectMapper mapObjectMapper, boolean copy) {
        if (copy) {
            this.mapObjectMapper = mapObjectMapper.copy();
        } else {
            this.mapObjectMapper = mapObjectMapper;
        }
    }

    @Override
    public Decoder<Object> getValueDecoder() {
        return decoder;
    }

    @Override
    public Encoder getValueEncoder() {
        return encoder;
    }

    @Override
    public ClassLoader getClassLoader() {
        if (mapObjectMapper.getTypeFactory().getClassLoader() != null) {
            return mapObjectMapper.getTypeFactory().getClassLoader();
        }

        return super.getClassLoader();
    }
}

redis工具类

public final class RedisUtils {

    public static final Codec REDISSON_CODEC;

    static {
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        REDISSON_CODEC = new RedissonCodec(om);
    }

    private RedisUtils() {}
}

代码使用

redissonClient.getConfig().setCodec(RedisUtils.REDISSON_CODEC);

redissonClient.getSet(redisKey, RedisUtils.REDISSON_CODEC).add(object);
redissonClient.getSet(redisKey, RedisUtils.REDISSON_CODEC).remove(object);