Spring Redis的StringRedisTemplate,RedisTemplate 使用介紹


我們先來看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序列化的數據看下圖:

 

 

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

那怎樣才能反序列出我們想要的User類型了,我們把上面注釋的兩行代碼放開,再次測試如下:

 

 

 最后能成功反序列出User類型,我們發現序列化的結果里面含有的序列化的類型信息,所以這也是能通過反射方式能得到我們想要的類型的原理。但他的優勢就比JdkSerializationRedisSerializer輕量很多,我們看JdkSerializationRedisSerializer序列化的結果為:

 

 

 

從結果我們可以看出對象序列化包含了類信息和屬性信息,這樣數據會冗余很多。

最后我們把前面通過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);

    }

主要添加了加紅的代碼,就能順利的反序列化出目標類型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM