redisTemplate,stringRedisTemplate序列化问题

今天遇到一个奇怪的bug,就是redisTemplate获取不到值,而stringRedisTemplate可以获取得到,执行代码就是以下

System.out.println(redisTemplate.opsForValue().get("name1"));
System.out.println(stringRedisTemplate.opsForValue().get("name1"));

debug打断点跟进去,DefaultValueOperations.java

public V get(Object key) {

        return execute(new ValueDeserializingRedisCallback(key) {

            @Override
            protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
//此处打开Evaluate Expression工具,计算rawKey.length=="name".getBytes().length,返回结果为false,可以定位问题在编码问题上
                return connection.get(rawKey);
            }
        }, true);
    }

继续debugger,可以到以下AbstractOperations.java

// utility methods for the template internal methods
    abstract class ValueDeserializingRedisCallback implements RedisCallback<V> {
        private Object key;

        public ValueDeserializingRedisCallback(Object key) {
            this.key = key;
        }

        public final V doInRedis(RedisConnection connection) {
         //此处是将key序列化为byte[]的,继续跟到rawKey方法中
            byte[] result = inRedis(rawKey(key), connection);
            return deserializeValue(result);
        }

        @Nullable
        protected abstract byte[] inRedis(byte[] rawKey, RedisConnection connection);
    }

继续跟到rawKey方法

byte[] rawKey(Object key) {

        Assert.notNull(key, "non null key required");
//继续跟keySerializer()
        if (keySerializer() == null && key instanceof byte[]) {
            return (byte[]) key;
        }

        return keySerializer().serialize(key);
}

恭喜找到源头了,这里获取的key的序列化对象。

RedisSerializer keySerializer() {
        return template.getKeySerializer();
}

推理中,StringRedisTempate可以获取到值,来看一下这里面的一部分代码,看看是否有可参考性

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

同理找到RedisTemplate中类似的这段代码

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

或者可以根据断点看到默认的Serializer是JdkSerializationRedisSerializer,与StringRedisTemplate中不一致。


image.png

解决:在自定义的RedisConfig中,参考StringRedisTemplate,将对应的几个序列化方法加入。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        template.setHashValueSerializer(RedisSerializer.string());
        return template;
    }

}

推荐阅读更多精彩内容