我们先来看StringRedisTemplate一个简单操作Redis的使用过程:

StringRedisTemplate redisTemplate = new StringRedisTemplate();
        //操作String
        redisTemplate.boundValueOps("test").set("val");
        User user = new User();
        user.setName("aaa");
        user.setAge(100);
        //操作Hash
        redisTemplate.boundHashOps("test").put("key1", user);

真正执行redis的set方法如下:

@Override
    public void set(K key, V value) {

        byte[] rawValue = rawValue(value);
        execute(new ValueDeserializingRedisCallback(key) {

            @Override
            protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
                connection.set(rawKey, rawValue);
                return null;
            }
        }, true);
    }
rawValue调用的是StringRedisTemplate的序列化方法valueSerializer().serialize(value)
ValueDeserializingRedisCallback内部调用的是valueSerializer().deserialize(value),
所以主要核心都是在RedisTemplate的序列化器中实现。

StringRedisTemplate继承自RedisTemplate<String,String>

public StringRedisTemplate() {
        setKeySerializer(RedisSerializer.string());
        setValueSerializer(RedisSerializer.string());
        setHashKeySerializer(RedisSerializer.string());
        setHashValueSerializer(RedisSerializer.string());
    }

从构造函数中可以看出设置了StringRedisSerializer序列化器,StringRedisSerializer的实现如下:

public class StringRedisSerializer implements RedisSerializer<String> {

    private final Charset charset;

    public static final StringRedisSerializer UTF_8 = new StringRedisSerializer(StandardCharsets.UTF_8);

    public StringRedisSerializer(Charset charset) {

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

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

    @Override
    public byte[] serialize(@Nullable String string) {
        return (string == null ? null : string.getBytes(charset));
    }
}

我们可以看到实现序列化serialize和反序列化deserialize只是将字符串转成字节数组,字节数组转字符串。

然后我们看RedisTemplate<Object,Object>,继承自RedisAccessor,RedisAccessor又继承了InitializingBean接口,我们可以看到afterPropertiesSet方法:

@Override
    public void afterPropertiesSet() {

        super.afterPropertiesSet();

        boolean defaultUsed = false;

        if (defaultSerializer == null) {

            defaultSerializer = new JdkSerializationRedisSerializer(
                    classLoader != null ? classLoader : this.getClass().getClassLoader());
        }

        if (enableDefaultSerializer) {

            if (keySerializer == null) {
                keySerializer = defaultSerializer;
                defaultUsed = true;
            }
            if (valueSerializer == null) {
                valueSerializer = defaultSerializer;
                defaultUsed = true;
            }
            if (hashKeySerializer == null) {
                hashKeySerializer = defaultSerializer;
                defaultUsed = true;
            }
            if (hashValueSerializer == null) {
                hashValueSerializer = defaultSerializer;
                defaultUsed = true;
            }
        }

        if (enableDefaultSerializer && defaultUsed) {
            Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");
        }

        if (scriptExecutor == null) {
            this.scriptExecutor = new DefaultScriptExecutor<>(this);
        }

        initialized = true;
    }

上面的主要是如果没设置序列化方式,就使用默认的JdkSerializationRedisSerializer,接下来我们看默认的序列化:

public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {

    private final Converter<Object, byte[]> serializer;
    private final Converter<byte[], Object> deserializer;

    public JdkSerializationRedisSerializer() {
        this(new SerializingConverter(), new DeserializingConverter());
    }

    public JdkSerializationRedisSerializer(@Nullable ClassLoader classLoader) {
        this(new SerializingConverter(), new DeserializingConverter(classLoader));
    }

    public JdkSerializationRedisSerializer(Converter<Object, byte[]> serializer, Converter<byte[], Object> deserializer) {

        Assert.notNull(serializer, "Serializer must not be null!");
        Assert.notNull(deserializer, "Deserializer must not be null!");

        this.serializer = serializer;
        this.deserializer = deserializer;
    }

    public Object deserialize(@Nullable byte[] bytes) {

        if (SerializationUtils.isEmpty(bytes)) {
            return null;
        }

        try {
            return deserializer.convert(bytes);
        } catch (Exception ex) {
            throw new SerializationException("Cannot deserialize", ex);
        }
    }

    @Override
    public byte[] serialize(@Nullable Object object) {
        if (object == null) {
            return SerializationUtils.EMPTY_ARRAY;
        }
        try {
            return serializer.convert(object);
        } catch (Exception ex) {
            throw new SerializationException("Cannot serialize", ex);
        }
    }
}

从上我们可以看到主要使用的是SerializingConverter和DeserializingConverter对象,接下来看SerializingConverter:

public class SerializingConverter implements Converter<Object, byte[]> {

    private final Serializer<Object> serializer;

    public SerializingConverter() {
        this.serializer = new DefaultSerializer();
    }

    @Override
    public byte[] convert(Object source) {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024);
        try  {
            this.serializer.serialize(source, byteStream);
            return byteStream.toByteArray();
        }
        catch (Throwable ex) {
            throw new SerializationFailedException("Failed to serialize object using " +
                    this.serializer.getClass().getSimpleName(), ex);
        }
    }
}
public class DefaultSerializer implements Serializer<Object> {

    @Override
    public void serialize(Object object, OutputStream outputStream) throws IOException {
        if (!(object instanceof Serializable)) {
            throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
                    "but received an object of type [" + object.getClass().getName() + "]");
        }
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(object);
        objectOutputStream.flush();
    }

}

通过如上可以看到主要使用的是jdk本省的对象序列化。

工作中我们一般喜欢使用json格式存储在redis中,spring redis也提供了Jackson2JsonRedisSerializer序列化器,使用方式如下:

Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//redisConnectionFactory这里是从容器注入的
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();

        User user = new User();
        user.setName("aaa");
        user.setAge(100);
        redisTemplate.boundValueOps("test").set(user);
        Object res = redisTemplate.boundValueOps("test").get();
        System.out.println("res:" + res);

但是最后我们发现res的类型并不是User类型,而是class java.util.LinkedHashMap类型。但这不是我们要的结果,下面直接使用Jackson2JsonRedisSerializer来分析下:

Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
//        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        User user = new User();
        user.setName("aaa");
        user.setAge(100);
        byte[] bt = jackson2JsonRedisSerializer.serialize(user);

        Object obj = jackson2JsonRedisSerializer.deserialize(bt);
        User user1 = (User) obj;
        System.out.println(user1);

通过调试我们拿到bt序列化的数据看下图:

StringRedisTemplate设置0点过期 stringredistemplate用法_User

 

 

 最后反序列化的结果就是 java.util.LinkedHashMap类型。

那怎样才能反序列出我们想要的User类型了,我们把上面注释的两行代码放开,再次测试如下:

StringRedisTemplate设置0点过期 stringredistemplate用法_序列化_02

 

 

 最后能成功反序列出User类型,我们发现序列化的结果里面含有的序列化的类型信息,所以这也是能通过反射方式能得到我们想要的类型的原理。但他的优势就比JdkSerializationRedisSerializer轻量很多,我们看JdkSerializationRedisSerializer序列化的结果为:

StringRedisTemplate设置0点过期 stringredistemplate用法_序列化_03

 

 

 

从结果我们可以看出对象序列化包含了类信息和属性信息,这样数据会冗余很多。

最后我们把前面通过Jackson2JsonRedisSerializer序列化redis的代码重新更改如下:

@Test
    public void testRedis2() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.afterPropertiesSet();

        User user = new User();
        user.setName("aaa");
        user.setAge(100);
        redisTemplate.boundValueOps("test").set(user);
        Object res = redisTemplate.boundValueOps("test").get();
        System.out.println("res:" + res);

    }

主要添加了加红的代码,就能顺利的反序列化出目标类型。