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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【小家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都是采用此策略序列化保存的。


相关文章
|
5月前
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
533 4
|
6月前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
307 0
|
6月前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
236 0
|
2月前
|
NoSQL Java Redis
Redis基本数据类型及Spring Data Redis应用
Redis 是开源高性能键值对数据库,支持 String、Hash、List、Set、Sorted Set 等数据结构,适用于缓存、消息队列、排行榜等场景。具备高性能、原子操作及丰富功能,是分布式系统核心组件。
343 2
|
4月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
174 32
|
3月前
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
233 0
|
5月前
|
前端开发 Java Maven
Spring 和 Spring Boot 之间的比较
本文对比了标准Spring框架与Spring Boot的区别,重点分析两者在模块使用(如MVC、Security)上的差异。Spring提供全面的Java开发基础设施支持,包含依赖注入和多种开箱即用的模块;而Spring Boot作为Spring的扩展,通过自动配置、嵌入式服务器等功能简化开发流程。文章还探讨了两者的Maven依赖、Mvc配置、模板引擎配置、启动方式及打包部署等方面的异同,展示了Spring Boot如何通过减少样板代码和配置提升开发效率。总结指出,Spring Boot是Spring的增强版,使应用开发、测试与部署更加便捷高效。
682 11
|
6月前
|
存储 人工智能 NoSQL
SpringBoot整合Redis、ApacheSolr和SpringSession
本文介绍了如何使用SpringBoot整合Redis、ApacheSolr和SpringSession。SpringBoot以其便捷的配置方式受到开发者青睐,通过引入对应的starter依赖,可轻松实现功能整合。对于Redis,可通过配置RedisSentinel实现高可用;SpringSession则提供集群Session管理,支持多种存储方式如Redis;整合ApacheSolr时,借助Zookeeper搭建SolrCloud提高可用性。文中详细说明了各组件的配置步骤与代码示例,方便开发者快速上手。
106 11
|
6月前
|
消息中间件 存储 Java
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
本教程介绍ActiveMQ的安装与基本使用。首先从官网下载apache-activemq-5.15.3版本,解压后即可完成安装,非常便捷。启动时进入解压目录下的bin文件夹,根据系统选择win32或win64,运行activemq.bat启动服务。通过浏览器访问`http://127.0.0.1:8161/admin/`可进入管理界面,默认用户名密码为admin/admin。ActiveMQ支持两种消息模式:点对点(Queue)和发布/订阅(Topic)。前者确保每条消息仅被一个消费者消费,后者允许多个消费者同时接收相同消息。
178 0
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
|
6月前
|
消息中间件 Java 微服务
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——发布/订阅消息的生产和消费
本文详细讲解了Spring Boot中ActiveMQ的发布/订阅消息机制,包括消息生产和消费的具体实现方式。生产端通过`sendMessage`方法发送订阅消息,消费端则需配置`application.yml`或自定义工厂以支持topic消息监听。为解决点对点与发布/订阅消息兼容问题,可通过设置`containerFactory`实现两者共存。最后,文章还提供了测试方法及总结,帮助读者掌握ActiveMQ在异步消息处理中的应用。
271 0