如标题,这是最近实习遇到的一个bug,当时正编写小程序端的接口,然后把小程序端的登录接口给我写了。
接手时,他的service层使用的是这种方式注入RedisTemplate工具的。
public class Jimmy1{
@Resource
private RedisTemplate<String, String> redisTemplate;
}
而我更喜欢使用的注入方式是这样的
@RequiredArgsConstructor
public class Jimmy2{
private final RedisTemplate<String, String> redisTemplate;
}
因此,我在造登录接口时,沿用他的这个@Resource注解注入的RedisTemplate将相关数据存入redis中。而在我自己的service层中,却使用@RequiredArgsConstructor方式注入的RedisTemplate去取数据。
于是,我的接口就报错了,查了日志。一直觉得自己写的没问题,可是确实是报错了,只能够在每一步都打上一个log.info(""),然后检查方法内每个示例对象是否正确。
经过排查发现。
假设原本的对象数据字符串是 4467,存入redis之后就变成了 "4467" ,使用@Resource的RedisTemplate会自动多加上了一个双引号。
而我自己使用@RequiredArgsConstructor的RedisTemplate,取出数据时却不会把 ""去掉。情况紧急,当时也没发现是注入方式不同引起的问题,于是就将计就计,把取出来的str = str.replaceAll("/"","");去除"引号,接口就正常使用了。。。。
后来逐步定位,才发现是注入方式不同的问题,但是不太确定,昨天加班把接下来两天的工作做完了,今天闲来有时间,就想着真的定位一下问题。
首先,我开了一个demo项目,然后造了两个接口,一个是http://127.0.0.1:8080/redis,一个是http://127.0.0.1:8080/redis/2 ,下方两个图是具体的代码逻辑。
两个controller层中,我使用两种注入方式去注入RedisTemplate示例对象,然后方法中,我把序列化器对象打印在控制台中。发现一个是jdk,一个是string,确实是使用了不一样的序列化器,造成了数据不一致的问题。
具体的getSerializer()方法如下,如下图RedisTemplate类中有一个属性变量为valueSerializer,因此我使用反射的方式获取对应的字段,然后再设置为可访问,然后传入对应的示例对象,获取该对象对应的valueSerializer字段。
private RedisSerializer<?> getSerializer(RedisTemplate<?, ?> template) throws Exception {
Field valueSerializerField = RedisTemplate.class.getDeclaredField("valueSerializer");
valueSerializerField.setAccessible(true);
return (RedisSerializer<?>) valueSerializerField.get(template);
}
问题分析出来了,接下来就好解决了。
1.要么就是保证都一起用@Resource注入,要么就是一起用@RequiredArgsConstructor注入,保证注入方式统一。
2.还有一种方式,因为正编在使用RedisTemplate的时候,是没有去配置类设置自定义的序列化器的。(我自己平时直接用StringRedisTemplate的,因此也没有去检查他有没有配置序列化器)那么我们就可以在config配置类使用@Configuration + @Bean的方式自定义序列化器,让springboot不要去选用默认的序列化器,就不会出现选用不同序列化器的问题了。
我自己没在优快云查到对应文章,希望对后来有相同问题的同学有帮助。