李锋镝的博客

  • 首页
  • 时间轴
  • 评论区显眼包🔥
  • 左邻右舍
  • 博友圈
  • 关于我
    • 关于我
    • 另一个网站
    • 我的导航站
    • 网站地图
    • 赞助
  • 留言
  • 🚇开往
Destiny
自是人生长恨水长东
  1. 首页
  2. 转载
  3. 技术
  4. 正文

SpringBoot集成Redis,从Redis中获取数据为null,但实际上Redis中是存在对应的数据的,是什么原因导致的呢?

2021年1月19日 210点热度 4人点赞 0条评论

最近项目中使用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.1
    port: 6379
    database: 1
    password: 123456
    timeout: 5000

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

@SpringBootTest
@RunWith(SpringRunner.class)
public class TokenTest {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public 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
    @ConditionalOnMissingBean
    public 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注解。同时,当然少不了对源码、注解等的使用的深入学习和了解。

 

除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/transport/2369

相关文章

  • SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
  • @Resource 和 @Autowired 的区别
  • Spring Boot 2.x使用PostgreSQL数据库
  • SpringBoot中@ImportAutoConfiguration注解与@Import和@EnableAutoConfiguration注解的区别
  • SpringBoot使用RestTemplate进行接口调用
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JAVA Redis SpringBoot
最后更新:2021年1月19日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >

文章评论

1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 57 58 60 61 62 63 64 65 66 67 69 72 74 76 77 78 79 80 81 82 85 86 87 90 92 93 94 95 96 97 98 99
取消回复

愿将腰下剑,直为斩楼兰。

那年今日(04月20日)

  • 1971年:中国著名法学家周鲠生逝世
  • 1901年:著名建筑学家梁思成出生于日本东京,祖籍广东新会
  • 1889年:德国纳粹党元首希特勒出生于奥地利布劳瑙
  • 1808年:法兰西第二帝国皇帝拿破仑出生
  • 429年:中国古代数学家祖冲之出生
  • 更多历史事件
最新 热点 随机
最新 热点 随机
Everything Claude Code 详细使用文档 配置Jackson使用字段而不是getter/setter来序列化和反序列化 这个域名注册整整十年了,十年时间,真快啊 Claude Code全维度实战指南:从入门到精通,解锁AI编程新范式 Apollo配置中心中的protalDB的作用是什么 org.apache.ibatis.plugin.Interceptor类详细介绍及使用
AI时代,个人技术博客的出路在哪里?使用WireGuard在Ubuntu 24.04系统搭建VPN这个域名注册整整十年了,十年时间,真快啊WordPress实现用户评论等级排行榜插件WordPress网站换了个字体,差点儿把样式换崩了做了一个WordPress文章热力图插件
使用WireGuard在Ubuntu 24.04系统搭建VPN 为什么 Apache Doris 是比 Elasticsearch 更好的实时分析替代方案? 妹妹的画【2019.07.03】 jmap命令(jdk1.8) 我要狠狠的反驳“公司禁止使用 Lombok ”的观点! Java之五种遍历Map集合的方式
标签聚合
SpringBoot 多线程 分布式 AI docker 数据库 AI编程 ElasticSearch Redis Spring JVM 设计模式 WordPress IDEA SQL JAVA 架构 日常 MySQL K8s
友情链接
  • Blogs·CN
  • Honesty
  • Mr.Sun的博客
  • 临窗旋墨
  • 哥斯拉
  • 彬红茶日记
  • 志文工作室
  • 懋和道人
  • 拾趣博客导航
  • 搬砖日记
  • 旧时繁华
  • 林羽凡
  • 瓦匠个人小站
  • 皮皮社
  • 知向前端
  • 蜗牛工作室
  • 韩小韩博客
  • 风渡言

COPYRIGHT © 2026 lifengdi.com. ALL RIGHTS RESERVED.

域名年龄

Theme Kratos Made By Dylan

津ICP备2024022503号-3

京公网安备11011502039375号