欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Redis实现自定义序列化方式

程序员文章站 2022-03-23 22:17:42
1. 如何实现redis的序列化?序列化:把对象转换为字节序列的过程称为对象的序列化。反序列化:把字节序列恢复为对象的过程称为对象的反序列化。序列化主要用于存储对象状态为另一种通用格式,比如存储为二进制、xml、json等等,把对象转换成这种格式就叫序列化,而反序列化通常是从这种格式转换回来。使用序列化主要是因为跨平台和对象存储的需求,因为网络上只允许字符串或者二进制格式,而文件需要使用二进制流格式,如果想把一个内存中的对象存储下来就必须使用序列化转换为xml(字符串)、json(字符串)或二进制(...

1. 如何实现redis的序列化?

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

序列化主要用于存储对象状态为另一种通用格式,比如存储为二进制、xml、json等等,把对象转换成这种格式就叫序列化,而反序列化通常是从这种格式转换回来。

使用序列化主要是因为跨平台和对象存储的需求,因为网络上只允许字符串或者二进制格式,而文件需要使用二进制流格式,如果想把一个内存中的对象存储下来就必须使用序列化转换为xml(字符串)、json(字符串)或二进制(流)

我们看看源码:redis的key和value为什么需要序列化?如何序列化?

① RedisAutoConfiguration的源码: Redis为我们提供了两个模板类RedisTemplate和StringRedisTemplate:

public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    //RedisTemplate的key和value都是Object类型的,如果进行网络传输或将数据存储到硬盘上就需对key和value进行序列化
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

② StringRedisTemplate的源码:可以看出他的键和值都只支持String类型

//StringRedisTemplate类继承RedisTemplate<String, String>
public class StringRedisTemplate extends RedisTemplate<String, String> {
    //将key和value都序列化为String类型的,也是只支持String类型的key和value
    public StringRedisTemplate() {
        this.setKeySerializer(RedisSerializer.string());
        this.setValueSerializer(RedisSerializer.string());
        this.setHashKeySerializer(RedisSerializer.string());
        this.setHashValueSerializer(RedisSerializer.string());
    }
}

③ RedisSerializer 的源码:可以看到redis提供的几种序列化方式:

StringRedisTemplate默认采用的是String的序列化策略**(StringRedisSerializer),保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略
(JdkSerializationRedisSerializer)**,保存的key和value都是采用此策略序列化保存的。用JdkSerializationRedisSerializer序列化的话,被序列化的对象必须实现Serializable接口。在存储内容时,除了属性的内容外还存了其它内容在里面,总长度长,且不容易阅读。

public interface RedisSerializer<T> {
    @Nullable
    byte[] serialize(@Nullable T var1) throws SerializationException;

    @Nullable
    T deserialize(@Nullable byte[] var1) throws SerializationException;

    static RedisSerializer<Object> java() {
        return java((ClassLoader)null);
    }

    static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
        return new JdkSerializationRedisSerializer(classLoader);
    }

    //保存对象为json,它不仅可以将对象序列化,还可以将对象转换为json字符串并保存到redis中,但需要和jackson配合一起使用。
    static RedisSerializer<Object> json() {
        return new GenericJackson2JsonRedisSerializer();
    }

    //将String字符串对象序列化为二进制字节数组,底层使用的StringRedisSerializer
    static RedisSerializer<String> string() {
        return StringRedisSerializer.UTF_8;
    }
}

RedisTemplate的key和value都支持Object类型;而StringRedisTemplate的key和value都支持String类型;现在我们希望Redis的key支持String类型,value支持Object类型:

key和hashKey : 推荐使用 StringRedisSerializer: 简单的字符串序列化;

value和hashValue: 推荐使用 GenericJackson2JsonRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置key的序列化方式
        template.setKeySerializer(RedisSerializer.string());
        // 设置value的序列化方式
        template.setValueSerializer(RedisSerializer.json());
        // 设置hash的key的序列化方式
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置hash的value的序列化方式
        template.setHashValueSerializer(RedisSerializer.json());

        template.afterPropertiesSet();
        return template;
    }
}

除此之外,还可以模仿StringRedisTemplate的序列化方式,自定义序列化方式对Object对象进行序列化:

StringRedisSerializer的源码:将String序列化为二进制byte数组;

public class StringRedisSerializer implements RedisSerializer<String> {
    private final Charset charset;
    public static final StringRedisSerializer US_ASCII;
    public static final StringRedisSerializer ISO_8859_1;
    public static final StringRedisSerializer UTF_8;

    public StringRedisSerializer() {
        this(StandardCharsets.UTF_8);
    }

    public StringRedisSerializer(Charset charset) {
        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }

    //将字节数组反序列化为String字符串
    public String deserialize(@Nullable byte[] bytes) {
        return bytes == null ? null : new String(bytes, this.charset);
    }

    //将String序列化为二进制byte[]数组
    public byte[] serialize(@Nullable String string) {
        return string == null ? null : string.getBytes(this.charset);
    }

    static {
        US_ASCII = new StringRedisSerializer(StandardCharsets.US_ASCII);
        ISO_8859_1 = new StringRedisSerializer(StandardCharsets.ISO_8859_1);
        UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);
    }
}

模仿StringRedisTemplate的序列化实现源码,对Object对象进行序列化:

public class MyStringRedisSerializer implements RedisSerializer<Object> {
    private final Charset charset;

    public MyStringRedisSerializer() {
        this(StandardCharsets.UTF_8);
    }

    public MyStringRedisSerializer(Charset charset) {
        Assert.notNull(charset, "Charset must not be null!");
        this.charset = charset;
    }

    @Override
    public String deserialize(byte[] bytes) {
        return (bytes == null ? null : new String(bytes, charset));
    }

    //将对象序列化为byte[]数组
    @Override
    public byte[] serialize(Object object) {
        //如果这个对象为null
        if (object == null) {
            return new byte[0];
        }
        //如果这个对象时String类型
        if (object instanceof String) {
            return object.toString().getBytes(charset);
        //如果这个对象不是String类型,就将这个对象转换为String类型后,然后转成byte字节数组
        } else {
            String string = JSON.toJSONString(object);
            return string.getBytes(charset);
        }
    }
}

配置一个RedisTemplate<String,Object>到Spring容器中:

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //key--String:定义一个 StringRedisSerializer 
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //value---Object:定义一个 MyStringRedisSerializer
        MyStringRedisSerializer myStringRedisSerializer = new MyStringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(myStringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(myStringRedisSerializer);
        return redisTemplate;
    }
}

本文地址:https://blog.csdn.net/qq_42764468/article/details/107685639

相关标签: Redis