【小家Spring】Spring Boot中使用RedisTemplate优雅的操作Redis,并且解决RedisTemplate泛型注入失败的问题(中)

简介: 【小家Spring】Spring Boot中使用RedisTemplate优雅的操作Redis,并且解决RedisTemplate泛型注入失败的问题(中)

RedisTemplate<String, String>和StringRedisTemplate是否相同呢?




基于这个疑问,做出如下测试:


    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    public void contextLoads() {
        System.out.println(redisTemplate == stringRedisTemplate); //true
    }


答案:实际注入的就是stringRedisTemplate对象。因为Spring的Bean默认都是单例的,所以返回true。源码一探究竟:

public class StringRedisTemplate extends RedisTemplate<String, String> {}


相信大家看到此处,就不用小编做过多的解释了。


RedisTemplate注入泛型为任意类型的实例,怎么办呢?


问题来了,我们从源码可以看出,Boot默认只为我们注入两个Bean,一个StringRedisTempate专门处理最常用的key和value都是String类型的。另外一个是RedisTemplate<Object, Object>,虽然能处理一切类型,但有时候使用起来确实不方便,我们希望在编译期就能知道泛型类型,写出更健壮的代码。


我们试试这么来:洗希望我的value对象是Person类型

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Person implements Serializable {
    private String name;
    private Integer age;
}


代码如下:


    @Autowired
    private RedisTemplate<String, Person> redisTemplate;
    @Test
    public void contextLoads() {
        System.out.println(redisTemplate);
    }


启动发现报错:


org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.fsx.run2.Run2ApplicationTests': Unsatisfied dependency expressed through field 'redisTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.core.RedisTemplate<java.lang.String, com.fsx.run2.bean.Person>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
  at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
  at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]


报错原因也容易看懂:找不到类型为RedisTemplate<String, Person>的Bean


那么这个问题该如何解决呢?不妨在使用RedisTemplate< K, V>时不指定具体的类型,修改代码如下:注入时不指定K、V的类型


    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void contextLoads() {
        System.out.println(redisTemplate); //org.springframework.data.redis.core.RedisTemplate@2c2c3947
    }


重启服务,发现没有报错了,注入成功。(这种解决方案其实也是最常用的解决方案)


RedisTemplate为什么会注入失败呢?


想到RedisTemplate在SpringBoot框架中是自动配置的,容器中默认的就是RedisTemplate的实例。想到这里,就需要翻下官网的文档,看看官网文档有没有什么说明。

image.png



我框出来的这句话特别重要,大概中文翻译如下:


如果你自己在配置类里面注入了一个Bean,那么将会替换Boot默认注册的Bean(您注入的bean的名称只有是restTemplate才会替换默认的,否则不替换)


请参加@ConditionalOnMissingBean这个注解,足以看见Spring的设计者的设计思想还是非常不错的:对修改关闭,对扩展开放。


我们做如下实验一:(bean的名字不要叫redisTemplate,否则Boot的Bean就不会再注入了)

自己注册一个bean

    @Bean("myRedisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }


测试代码如下:


    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void contextLoads() {
        Object redisTemplate1 = applicationContext.getBean("redisTemplate");
        Object myRedisTemplate2 = applicationContext.getBean("myRedisTemplate");
        System.out.println(redisTemplate1); //RedisTemplate@5ec6a1b6
        System.out.println(myRedisTemplate2); //RedisTemplate@40013051
        //我们发现这样注入进来的是Boot默认注册的那个bean
        System.out.println(this.redisTemplate); //RedisTemplate@5ec6a1b6
    }


惊奇一:Spring容器内出现了多个类型一样的Bean,但Autowaired竟然成功了(这个绝提原因,读者可以去了解一下Spring4开始的泛型依赖注入,Spring在这方面有处理)

惊奇二:Spring自动注入,注入的为Boot给自动注入进去的Bean,而不是我们自己注入的(我感觉这应该和先后顺序有管。并没有强制的识别“系统”,虽然我没看源码,但若有研究过的,可以跟我讨论)


我们改一下,把我们自己注入的bean泛型改一下:


    @Bean("myRedisTemplate")
    public RedisTemplate<String, Person> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Person> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }


测试代码:


    @Test
    public void contextLoads() {
        Object redisTemplate1 = applicationContext.getBean("redisTemplate");
        Object myRedisTemplate2 = applicationContext.getBean("myRedisTemplate");
        System.out.println(redisTemplate1); //RedisTemplate@2c2c3947
        System.out.println(myRedisTemplate2); //RedisTemplate@4a62062a
        System.out.println(this.redisTemplate); //RedisTemplate@2c2c3947
        System.out.println(this.personRedisTemplate); //edisTemplate@4a62062a
    }


由此我们看出,Spring很好的实现了泛型依赖注入。很强大有木有,太方便了。虽然类型都一样,但是泛型不一样,强大的Spring还是能够很好的区分开。


那么在实际的开发中,如果我们需要操作上面Person类型,怎么做呢?


建议:注入restTemplate的时候不指定类型,而在在获取处理器的时候,手动指定泛型即可

    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void contextLoads() {
        ValueOperations<String, Person> valueOperations = redisTemplate.opsForValue();
        valueOperations.set("aaa", new Person("fsx", 24));
        Person p = valueOperations.get("aaa"); //Person(name=fsx, age=24)
        System.out.println(p);
    }


我们发现不需要特意的去指定restTemplate的泛型,而是在获得处理器的时候指定就好了。因为restTemplate默认可以处理一切类型。(Spring内部做了类型强转,所以不会出问题)


当然,你自己注册一个指定类型,也是没毛病的


StringRedisTemplate与RedisTemplate的区别


1.两者的关系是StringRedisTemplate继承RedisTemplate。


2.两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。


3.默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。


4。StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。


相关文章
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1355 4
|
8月前
|
NoSQL Java 网络安全
SpringBoot启动时连接Redis报错:ERR This instance has cluster support disabled - 如何解决?
通过以上步骤一般可以解决由于配置不匹配造成的连接错误。在调试问题时,一定要确保服务端和客户端的Redis配置保持同步一致。这能够确保SpringBoot应用顺利连接到正确配置的Redis服务,无论是单机模式还是集群模式。
673 5
|
NoSQL Java 关系型数据库
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
本文介绍在 Spring Boot 中集成 Redis 的方法。Redis 是一种支持多种数据结构的非关系型数据库(NoSQL),具备高并发、高性能和灵活扩展的特点,适用于缓存、实时数据分析等场景。其数据以键值对形式存储,支持字符串、哈希、列表、集合等类型。通过将 Redis 与 Mysql 集群结合使用,可实现数据同步,提升系统稳定性。例如,在网站架构中优先从 Redis 获取数据,故障时回退至 Mysql,确保服务不中断。
471 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
|
9月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
788 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
11月前
|
NoSQL Java Redis
Redis基本数据类型及Spring Data Redis应用
Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。
792 2
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
381 32
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
833 0
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
417 36
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
289 2
一键注入 Spring 成员变量,顺序编程
|
NoSQL Java API
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Spring Boot 集成 Redis
本文介绍了在Spring Boot中集成Redis的方法,包括依赖导入、Redis配置及常用API的使用。通过导入`spring-boot-starter-data-redis`依赖和配置`application.yml`文件,可轻松实现Redis集成。文中详细讲解了StringRedisTemplate的使用,适用于字符串操作,并结合FastJSON将实体类转换为JSON存储。还展示了Redis的string、hash和list类型的操作示例。最后总结了Redis在缓存和高并发场景中的应用价值,并提供课程源代码下载链接。
2770 0