今天遇到一个奇怪的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;
}
}
网友评论