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,一经查实,立即删除!

相关文章

数据分析告诉你为什么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…

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

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

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 …

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

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

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

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

SpringBoot集成Google开源图片处理框架,贼好用!

1、序在实际开发中&#xff0c;难免会对图片进行一些处理&#xff0c;比如图片压缩之类的&#xff0c;而其中压缩可能就是最为常见的。最近&#xff0c;我就被要求实现这个功能&#xff0c;原因是客户那边嫌速度过慢。借此机会&#xff0c;今儿就给大家介绍一些一下我做这个功能…

推荐一款开源数据库设计工具,比PowerDesigner更好用!

最近有个新项目刚过完需求&#xff0c;正式进入数据库表结构设计阶段&#xff0c;公司规定统一用数据建模工具 PowerDesigner。但我并不是太爱用这个工具&#xff0c;因为它的功能实在是太多了&#xff0c;显得很臃肿繁琐&#xff0c;而平时设计表用的也就那么几个功能。这里找…

cocos2d-x lua 学习笔记(1) -- 环境搭建

Cocos2d-x 3.0以上版本的环境搭建和之前的Cocos2d-x 2.0 版差异较大的,同时从Cocos2d-x 3.0项目打包成apk安卓应用文件&#xff0c;搭建安卓环境的步骤有点繁琐&#xff0c;但搭建一次之后&#xff0c;以后就会非常快捷&#xff01;OK&#xff0c;现在就开始搭建环境吧&#xf…

Socket粘包问题的3种解决方案,最后一种最完美!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在 Java 语言中&#xff0c;传统的 Socket 编程分为两种实现方式&#xff0c;这两种实现方式也对应着两种不同的传输层协议…

【万里征程——Windows App开发】控件大集合1

添加控件的方式有多种&#xff0c;大家更喜欢哪一种呢&#xff1f; 1&#xff09;使用诸如 Blend for Visual Studio 或 Microsoft Visual Studio XAML 设计器的设计工具。 2&#xff09;在 Visual Studio XAML 编辑器中将控件添加到 XAML 标记中。 3&#xff09;在代码中添…

从String中移除空白字符的多种方式!?差别竟然这么大!

字符串&#xff0c;是Java中最常用的一个数据类型了。我们在日常开发时候会经常使用字符串做很多的操作。比如字符串的拼接、截断、替换等。这一篇文章&#xff0c;我们介绍一个比较常见又容易被忽略的一个操作&#xff0c;那就是移除字符串中的空格。其实&#xff0c;在Java中…

不要再用main方法测试代码性能了,用这款JDK自带工具

前言作为软件开发人员&#xff0c;我们通常会写一些测试程序用来对比不同算法、不同工具的性能问题。而最常见的做法是写一个main方法&#xff0c;构造模拟场景进行并发测试。如果细心的朋友可能已经发现&#xff0c;每次测试结果误差很大&#xff0c;有时候测试出的结果甚至与…

Java中Properties类的操作

http://www.cnblogs.com/bakari/p/3562244.html Java中Properties类的操作 知识学而不用&#xff0c;就等于没用&#xff0c;到真正用到的时候还得重新再学。最近在看几款开源模拟器的源码&#xff0c;里面涉及到了很多关于Properties类的引用&#xff0c;由于Java已经好久没用…

复盘线上的一次OOM和性能优化!

来源&#xff1a;r6d.cn/ZazN上周五&#xff0c;发布前一周的服务器小动荡????事情回顾上周五&#xff0c;通过Grafana监控&#xff0c;线上环境突然出现CPU和内存飙升的情况&#xff1a;但是看到网络输入和输入流量都不是很高&#xff0c;所以网站被别人攻击的概率不高&am…

阅读源码的 4 个绝技,我必须分享给你!

为什么要阅读源码&#xff1f;1.在通用型基础技术中提高技术能力在 JAVA 领域中包含 JAVA 集合、Java并发(JUC)等&#xff0c; 它们是项目中使用的高频技术&#xff0c;在各种复杂的场景中选用合适的数据结构、线程并发模型&#xff0c;合理控制锁粒度等都能显著提高应用程序的…

innerHTML、innerText和outerHTML、outerText的区别

1、区别描述如下&#xff1a; innerHTML 设置或获取位于对象起始和结束标签内的 HTMLouterHTML 设置或获取对象及其内容的 HTML 形式innerText 设置或获取位于对象起始和结束标签内的文本outerText 设置(包括标签)或获取(不包括标签)对象的文本innerText和outerText在获取时是相…

Socket粘包问题终极解决方案—Netty版(2W字)!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;上一篇我们写了《Socket粘包问题的3种解决方案》&#xff0c;但没想到评论区竟然炸了。介于大家的热情讨论&#xff0c;以及…

Java高质量代码之 — 泛型与反射

在Java5后推出了泛型,使我们在编译期间操作集合或类时更加的安全,更方便代码的阅读,而让身为编译性语言的Java提供动态性的反射技术,更是在框架开发中大行其道,从而让Java活起来,下面看一下在使用泛型和反射需要注意和了解的事情 1.Java的泛型是类型擦除的 Java中的泛型是…