Spring Boot集成Redis,这个坑把我害惨了!

最近项目中使用SpringBoot集成Redis,踩到了一个坑:从Redis中获取数据为null,但实际上Redis中是存在对应的数据的。是什么原因导致此坑的呢?

本文就带大家从SpringBoot集成Redis、所踩的坑以及自动配置源码分析来学习一下SpringBoot中如何正确的使用Redis。

SpringBoot集成Redis

在SpringBoot项目中只需在pom文件中引入Redis对应的starter,配置Redis连接信息即可进行使用了。pom依赖引入:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

对应application配置文件配置:

spring:redis:host: 127.0.0.1port: 6379database: 1password: 123456timeout: 5000

通过以上两项配置即完成了Redis的集成,下面便是具体的使用,这里以单元测试的形式呈现。

@SpringBootTest
@RunWith(SpringRunner.class)
public class TokenTest {@Autowiredprivate RedisTemplate redisTemplate;@Testpublic void getValue() {Object value = redisTemplate.opsForValue().get("1");System.out.println("value:" + value);}
}

可以看到直接通过@Autowired注入RedisTemplate之后,即可调用RedisTemplate提供的方法操作。RedisTemplate提供了丰富的Redis操作方法,具体使用查看相应的API即可,这里不再拓展。

项目中遇到的坑

回归到最开始的问题:从Redis中获取数据为null,但实际上Redis中是存在对应的数据的。

其实问题表象很诡异,但问题的原因很简单,就是Redis中存数据和取数据时采用了不同的RedisTemplate导致的。

在SpringBoot中,针对Redis的自动配置类默认会初始化两个RedisTemplate,先来看一下RedisAutoConfiguration中源码:

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {@Bean@ConditionalOnMissingBean(name = {"redisTemplate"})public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {RedisTemplate<Object, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}@Bean@ConditionalOnMissingBeanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}
}

可以看到RedisAutoConfiguration中初始化了两个RedisTemplate的bean。第一个Bean类型为RedisTemplate<Object, Object>,Bean的名称为redisTemplate,而且是当容器中不存在对应的Bean name时才会进行初始化。第二Bean类型为StringRedisTemplate,Bean的名称为stringRedisTemplate,该类继承自RedisTemplate<String, String>。

也就说一个Bean是针对Object对象处理的,一个是针对String对象进行处理的。

导致出现坑的原因便是set时注入的是RedisTemplate<Object, Object>,而获取时注入的是StringRedisTemplate。这么明显的错误应该很容易排查的啊?

问题为什么隐藏的那么深?

如果直接是因为两处类型不一致导致的,的确很好排查,看一下注入的RedisTemplate即可。

但问题难以排查,还因为另外一个因素:@Resource和@Autowired注入的问题。

默认情况下@Resource采用先根据bean名称注入,找不到再根据类型注入,而@Autowired默认采用根据类型注入。项目获取数据时采用了@Resource注入方式,如下:

@Resource
private RedisTemplate<String, String> redisTemplate;

而存储时采用的是@Autowired注入的:

@Autowired
private RedisTemplate<String, String> redisTemplate;

上面两种形式的注入,在只存在单个实例时好像并不是什么问题,要么其中一个直接报错,要么注入成功。但当像上述场景,出现了两个RedisTemplate时,问题就变得隐蔽了。

当采用@Autowired时,根据类型注入,直接注入了RedisTemplate<String, String>的bean,因为它们的类型都是String的。

而当使用@Resource注入时,默认采用的是根据名称匹配,源码中可以看到redisTemplate对应的类型为RedisTemplate<Object, Object>。因此,两处注入了不同的RedisTemplate,于是就导致了获取时获取不到值的问题。

解决方案

找到问题的根源之后,解决问题便容易多了。

方案一,将@Resource的注入改为@Autowired。

方案二:将@Resource注入的bean名称由redisTemplate改为stringRedisTemplate。当然根据具体业务场景还有其他解决方案。

小结

关于SpringBoot集成Redis其实很简单,SpringBoot已经帮我们做了大多数的事情,但因为默认初始化了两个RedisTemplate,再加上@Autowired和@Resource注解的区别就导致了问题的复杂度。因此,在使用的过程中尽量保持各处采用一致的规范,阿里Java开发手册推荐使用@Resource注解。同时,当然少不了对源码、注解等的使用的深入学习和了解。


往期推荐

文件写入的6种方法,这种方法性能最好


线程池的7种创建方式,强烈推荐你用它...


求求你,别再用wait和notify了!


关注我,每天陪你进步一点点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545094.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

www(apache)服务器的基本设置

1、安装yum install httpdyum install mysql-server*yum install mysql-develyum install phpyum install php-develyum install php-mysql2、httpd 和 mysql 的启动停止a、httpd/etc/init.d/httpd start/etc/init.d/httpd stop注&#xff1a;Apache自行提供一个script&#xf…

数据分析告诉你为什么Apple Watch会大卖?

摘要: 不管是无敌创意还是无聊鸡肋&#xff0c;苹果手表还是来了。眼下它上市在即&#xff0c;将率先登陆9个国家或地区——包括中国。根据凌晨发布会上公布的内容&#xff0c;Apple Watch采用全新的压感触屏和蓝宝石镜面&#xff0c;能够记录健康数据、同步手机信息 ...不管是…

putc函数_C语言中的putc()函数与示例

putc函数C语言中的putc()函数 (putc() function in C) The putc() function is defined in the <stdio.h> header file. putc()函数在<stdio.h>头文件中定义。 Prototype: 原型&#xff1a; int putc(const char ch, FILE *filename);Parameters: const char ch,…

编程中的21个坑,你占几个?

前言最近看了某客时间的《Java业务开发常见错误100例》&#xff0c;再结合平时踩的一些代码坑&#xff0c;写写总结&#xff0c;希望对大家有帮助&#xff0c;感谢阅读~1. 六类典型空指针问题包装类型的空指针问题级联调用的空指针问题Equals方法左边的空指针问题ConcurrentHas…

单词:131209

N&#xff1a; Acting 表演、演艺界 Cooperative 合作企业 Images 影像、图像 Information 信息 Projects 项目、工程 Role 角色、作用 Technology 技术 Victims 受害人 Characters 人物、性格 Desire 渴望、欲望 Diversity 多样性 Escape 逃走&#xff0c;逃脱 P…

Yii 2 美化 url

在使用 yii 1.x 中&#xff0c;我们都知道美化 url 是在配置文件中进行配置&#xff0c;那其实在 yii 2.x 中也还是一样的&#xff0c;只是配置的值不同了而已&#xff0c;接下来我们就看看如何在 yii 2.x 中美化 url 打开 config\web.php, 在 components 这个大数组里面添加以…

java timezone_Java TimeZone getAvailableIDs()方法与示例

java timezoneTimeZone类的getAvailableIDs()方法 (TimeZone Class getAvailableIDs() method) Syntax: 句法&#xff1a; public static String [] getAvailableIDs()public static String [] getAvailableIDs(int r_off);getAvailableIDs() method is available in java.uti…

Mybatis使用的9种设计模式,真是太有用了

crazyant.net/2022.html虽然我们都知道有26个设计模式&#xff0c;但是大多停留在概念层面&#xff0c;真实开发中很少遇到&#xff0c;Mybatis源码中使用了大量的设计模式&#xff0c;阅读源码并观察设计模式在其中的应用&#xff0c;能够更深入的理解设计模式。Mybatis至少遇…

Android 禁止屏幕旋转 旋转屏幕时保持Activity内容

Android 禁止屏幕旋转 & 旋转屏幕时保持Activity内容 1.在应用中固定屏幕方向。 在AndroidManifest.xml的activity中加入: android:screenOrientation”landscape” 属性即可(landscape是横向&#xff0c;portrait是纵向)。 OK 2.随屏幕旋转时&a…

Java PushbackInputStream skip()方法与示例

PushbackInputStream类skip()方法 (PushbackInputStream Class skip() method) skip() method is available in java.io package. skip()方法在java.io包中可用。 skip() method is used to skip the given number of bytes of content from this PushbackInputStream. When th…

jsp页面传中文到action中乱码问题

在用jspstruts2做个网站时&#xff0c;当要直接传中文字符到action中的方法总是出现乱码&#xff0c;在网上试了一些方法没有达到效果&#xff0c;一下两种方法是本人用过不会出现乱码的。 方法一&#xff1a;public void setSingerGender(String singerGender) {try {this.sin…

Java 生成随机数的 5 种方式,你知道几种?

1. Math.random() 静态方法产生的随机数是 0 - 1 之间的一个 double&#xff0c;即 0 < random < 1。使用&#xff1a;for (int i 0; i < 10; i) {System.out.println(Math.random()); }结果&#xff1a;0.3598613895606426 0.2666778145365811 0.25090731064243355 …

linux进程的管理,显示及杀死

ps 命令是用来查看目前系统中&#xff0c;有哪些正在执行&#xff0c;以及他们的执行情况。可以不加任何参数。 显示详细的进程信息1、ps -a&#xff1a;意思是说显示当前终端的所有进程信息2、ps -u&#xff1a;以用户的格式显示进程信息3、ps -x&#xff1a;显示后台进程运行…

Java OutputStreamWriter flush()方法与示例

OutputStreamWriter类flush()方法 (OutputStreamWriter Class flush() method) flush() method is available in java.io package. flush()方法在java.io包中可用。 flush() method is used to flush this stream. flush()方法用于刷新此流。 flush() method is a non-static m…

percona-toolkit工具包的使用教程

percona-toolkit工具包的使用教程之介绍和安装http://blog.chinaunix.net/uid-20639775-id-3206802.htmlpercona-toolkit工具包的使用教程之开发工具类使用http://blog.chinaunix.net/uid-20639775-id-3207926.htmlpercona-toolkit工具包的使用教程之性能类工具http://blog.chi…

MySQL为Null会导致5个问题,个个致命!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;正式开始之前&#xff0c;我们先来看下 MySQL 服务器的配置和版本号信息&#xff0c;如下图所示&#xff1a;“兵马未动粮草…

任务调度的使用crontab

任务调度的使用crontab1、设置任务crontab -e2、每隔一定时间去执行 date > /home/mydate11&#xff09;希望&#xff0c;每天凌晨2&#xff1a;00去执行 date >> /home/mydate2可以再crontab -e中加入0 2 * * * date >> /home/mydate22&#xff09;希望每分钟去…

sql 存储过程返回值 变量名

return 语句返回值&#xff0c;前台调用的参数名称为 RETURN_VALUE

Java Integer类shortValue()方法与示例

整数类shortValue()方法 (Integer class shortValue() method) shortValue() method is available in java.lang package. shortValue()方法在java.lang包中可用。 shortValue() method is used to return the value denoted by this Integer object converted to type short (…

Spring Boot 解决跨域问题的 3 种方案!

作者 | telami来源 | telami.cn/2019/springboot-resolve-cors前后端分离大势所趋&#xff0c;跨域问题更是老生常谈&#xff0c;随便用标题去google或百度一下&#xff0c;能搜出一大片解决方案&#xff0c;那么为啥又要写一遍呢&#xff0c;不急往下看。问题背景&#xff1a;…