当前位置: 移动技术网 > IT编程>开发语言>JavaScript > Redis实现自定义序列化方式

Redis实现自定义序列化方式

2020年07月31日  | 移动技术网IT编程  | 我要评论

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网