【Spring Boot 源码学习】RedisAutoConfiguration 详解

news2024/12/28 19:08:30

Spring Boot 源码学习系列

在这里插入图片描述

RedisAutoConfiguration 详解

  • 引言
  • 往期内容
  • 主要内容
    • 1. Spring Data Redis
    • 2. RedisAutoConfiguration
      • 2.1 加载自动配置组件
      • 2.2 过滤自动配置组件
        • 2.2.1 涉及注解
        • 2.2.2 redisTemplate 方法
        • 2.2.3 stringRedisTemplate 方法
  • 总结

引言

上篇博文,Huazie 带大家从源码角度分析了 Spring Boot 内置的 http 编码功能,进一步熟悉了自动配置的装配流程。本篇趁热打铁,继续带大家分析 Spring Boot 内置的有关 Redis 的自动配置类【RedisAutoConfiguration】。

在这里插入图片描述

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

Spring Boot 源码学习
Spring Boot 项目介绍
Spring Boot 核心运行原理介绍
【Spring Boot 源码学习】@EnableAutoConfiguration 注解
【Spring Boot 源码学习】@SpringBootApplication 注解
【Spring Boot 源码学习】走近 AutoConfigurationImportSelector
【Spring Boot 源码学习】自动装配流程源码解析(上)
【Spring Boot 源码学习】自动装配流程源码解析(下)
【Spring Boot 源码学习】深入 FilteringSpringBootCondition
【Spring Boot 源码学习】OnClassCondition 详解
【Spring Boot 源码学习】OnBeanCondition 详解
【Spring Boot 源码学习】OnWebApplicationCondition 详解
【Spring Boot 源码学习】@Conditional 条件注解
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解

主要内容

1. Spring Data Redis

Spring Data RedisSpring Data 家族的一部分,它提供了从 Spring 应用程序中轻松配置和访问 Redis 的功能。

我们来看看官方介绍的特性:

  • 连接包作为多个 Redis 驱动程序( LettuceJedis )的低级别抽象。
  • Redis 驱动程序异常转换为 Spring 的可移植数据访问异常层次结构。
  • 提供各种 Redis 操作、异常转换和序列化支持的 RedisTemplate
  • 支持发布订阅(例如用于消息驱动 POJO 的消息监听器容器)。
  • 支持 Redis SentinelRedis Cluster
  • 使用 Lettuce 驱动程序的响应式 API
  • 支持 JDKStringJSONSpring 对象 / XML 映射序列化器。
  • Redis 上实现 JDK 集合。
  • 支持原子计数器类。
  • 支持排序和管道功能。
  • 专用于 SORTSORT/GET模式和支持返回批量值的功能。
  • Spring 缓存抽象提供 Redis 实现。
  • 自动实现 Repository 接口,包括使用 @EnableRedisRepositories 支持自定义查询方法。
  • 对存储库提供 CDI 支持。

Spring Data Redis 中,我们可以直接使用 RedisTemplate 及其相关的类来操作 Redis。虽然 RedisConnection 提供了接受和返回二进制值(字节数组)的低级方法,但 RedisTemplate 负责序列化和连接管理,使用户可以无需处理这些细节。

RedisTemplate 还提供了操作视图(按照 Redis 命令参考进行分组),这些视图提供了丰富、通用的接口,用于针对特定类型或特定键进行操作(通过 KeyBound 接口实现),如下表所示:

接口描述
GeoOperationsRedis地理空间操作,例如GEOADD、GEORADIUS等。
HashOperationsRedis哈希操作
HyperLogLogOperationsRedis键绑定哈希操作
ListOperationsRedis列表操作
SetOperationsRedis集合操作
ValueOperationsRedis字符串(或值)操作
ZSetOperationsRedis有序集合操作
BoundGeoOperationsRedis键绑定地理空间操作
BoundHashOperationsRedis键绑定哈希操作
BoundKeyOperationsRedis键绑定操作
BoundListOperationsRedis键绑定列表操作
BoundSetOperationsRedis键绑定集合操作
BoundValueOperationsRedis键绑定字符串(或值)操作
BoundZSetOperationsRedis键绑定有序集合操作

下面我们来看看相关的 Spring 配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>
  <!-- redis 模板定义 -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory"/>

</beans>

一旦配置完成,Redis 模板就是线程安全的,并且可以在多个实例之间重用。

RedisTemplate 使用基于 Java 的序列化器进行大部分操作。也就意味着通过模板写入或读取的任何对象都是通过 Java 进行序列化和反序列化的。

我们也可以更改模板上的序列化机制,可以添加如下配置:

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory"/>
    <property name="keySerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    </property>
    <property name="valueSerializer">
        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    </property>
    <property name="hashKeySerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    </property>
    <property name="hashValueSerializer">
        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    </property>
</bean>

而 Redis 模块提供了几个序列化器的实现,有关这些实现大家可以查看 org.springframework.data.redis.serializer 包。

在这里插入图片描述

还可以将任何序列化程序设置为 null,并通过设置 enableDefaultSerializer 属性为 false 来使用RedisTemplate 与原始字节数组一起使用。

注意: 模板要求所有键都不为空。但是,只要底层序列化程序接受值,值就可以为空。

下面我们可以注入 RedisTemplate,并调用 RedisTemplate 的方法进行存储、查询、删除等操作。

@Autowired
private RedisTemplate<String, Object> redisTemplate;


// 存储数据
redisTemplate.opsForValue().set("key", "value");
// 查询数据
Object value = redisTemplate.opsForValue().get("key");
// 删除数据
redisTemplate.delete("key");

对于需要特定模板视图的情况,声明视图作为依赖项并注入模板。容器会自动执行转换,消除opsFor[X] 调用,如下所示的示例:

public class Example {	
	// inject the template as ListOperations
	@Resource(name="redisTemplate")
	private ListOperations<String, String> listOps;
	
	public void addLink(String userId, URL url) {
	  listOps.leftPush(userId, url.toExternalForm());
	}
}

当然 Spring Data Redis 肯定不止上述这些,有需要深入了解的读者们,请看如下:

参考: Spring Data Redis 官方文档

2. RedisAutoConfiguration

那么 Spring Data Redis 的 RedisTemplate 的自动配置在 Spring Boot 是如何实现的呢?

Spring Boot 是通过内置的 RedisAutoConfiguration 配置类来完成这一功能。下面我们具体分析一下:

注意: 以下涉及 Spring Boot 源码 均来自版本 2.7.9,其他版本有所出入,可自行查看源码。

2.1 加载自动配置组件

从之前的《【Spring Boot 源码学习】自动装配流程源码解析(上)》中,我们知道 Spring Boot 内部针对自动配置类,会读取如下两个配置文件:

  • META-INF/spring.factories
  • META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

在这里插入图片描述

实际上 在 Spring Boot 2.7.9 版本中, Spring Boot 自己内部的 META-INF/spring.factories 中有关自动配置的注册类的配置信息已经被去除掉了,不过其他外围的 jar 中可能有自己的 META-INF/spring.factories 文件,它里面也有关于自动配置注册类的配置信息;

而 Spring Boot 内置的 RedisAutoConfiguration 配置类,则是配置在上述的第二个配置文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中。

在这里插入图片描述

2.2 过滤自动配置组件

上述自动配置加载完之后,就来到了 《【Spring Boot 源码学习】自动装配流程源码解析(下)》 介绍的 过滤自动配置组件 逻辑。

这部分数据对应的配置内容在 META-INF/spring-autoconfigure-metadata.properties 文件中:

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration=
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.ConditionalOnClass=org.springframework.data.redis.core.RedisOperations

显然这里涉及到了 ConditionalOnClass 注解,我们翻看 RedisAutoConfiguration 配置类的源码,如下:

@AutoConfiguration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		// 。。。
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		// 。。。
	}

}
2.2.1 涉及注解

我们先来看看上述 RedisAutoConfiguration 配置类涉及到的注解,如下:

  • @AutoConfiguration : 该类是一个自动配置类,Spring Boot 会根据项目中的依赖自动配置这个类的实例。
  • @ConditionalOnClass(RedisOperations.class) :只有在项目中引入了RedisOperations类(通常由spring-data-redis库提供)的情况下,才会加载这个配置类。
  • @EnableConfigurationProperties(RedisProperties.class) :启用RedisProperties 类作为配置属性。这样,我们就可以在 application.propertiesapplication.yml 文件中定义 Redis 的相关配置。
  • @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) :导入注解,表示导入 LettuceConnectionConfigurationJedisConnectionConfiguration 这两个类。这两个类通常用于配置 Redis 连接的具体实现,例如使用 Lettuce 还是 Jedis 等。
  • @Bean :用于声明一个方法创建的对象是一个 Spring 管理的 BeanSpring 容器会自动管理这个 Bean 的生命周期,包括依赖注入、初始化和销毁等。
  • @ConditionalOnMissingBean :只有在当前 Spring 容器中不存在指定类型的 Bean 时,才会执行被注解的方法。这样可以用于确保在需要的时候才创建某个 Bean,避免重复创建。
  • @ConditionalOnSingleCandidate:只有在当前上下文中存在且只有一个指定类型的 bean 候选者时,才会创建这个 bean

其中 RedisProperties 类的属性值对应着 application.ymlapplication.properties 中的配置,通过注解@ConfigurationProperties(prefix = "spring.redis") 实现的属性注入。

有关属性注入的内容后续笔者会另外介绍,我们先来看看RedisProperties 类相关的部分源码 和 对应的配置参数:

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

	// 。。。

	// Redis 服务器主机地址.
	private String host = "localhost";
	
	// 。。。

	// Redis 服务器的端口
	private int port = 6379;

	private Sentinel sentinel;

	private Cluster cluster;

	private final Jedis jedis = new Jedis();

	private final Lettuce lettuce = new Lettuce();

	// Redis 连接池配置
	public static class Pool {
		// 。。。
	}
	// Redis 集群配置
	public static class Cluster {
		// 。。。
	}
	// Redis 哨兵配置
	public static class Sentinel {
		// 。。。
	}
	// Jedis 客户端配置
	public static class Jedis {

		// Jedis 连接池配置
		private final Pool pool = new Pool();
	}
	// Lettuce 客户端配置
	public static class Lettuce {
		// Lettuce 连接池配置
		private final Pool pool = new Pool();

		private final Cluster cluster = new Cluster();
	}
}

然后在 application.properties 中,我们就可以添加类似如下的配置:

# Redis 单机配置
spring.redis.host=127.0.0.1
spring.redis.port=31113

# Redis 集群配置
# nodes属性是Redis集群节点的地址和端口,用逗号分隔。
spring.redis.cluster.nodes=192.168.1.1:7000,192.168.1.2:7001,192.168.1.3:7002
# max-redirects属性是最大重定向次数,用于处理节点故障的情况。
spring.redis.cluster.max-redirects=3

# mymaster是哨兵模式下的主节点名称。
spring.redis.sentinel.master=mymaster
# nodes是哨兵模式下的从节点地址和端口。
spring.redis.sentinel.nodes=192.168.1.1:26379,192.168.1.2:26379,192.168.1.3:26379

# ...其他配置省略
2.2.2 redisTemplate 方法

先来看看 redisTemplate 方法的源码【Spring Boot 2.7.9】:

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

上述逻辑表示只有在当前上下文中不存在名为 "redisTemplate"Bean 时,才会创建一个名为 redisTemplateRedisTemplate Bean,并将其与一个可用的 Redis 连接工厂关联起来。

2.2.3 stringRedisTemplate 方法

我们再来看看 stringRedisTemplate 方法的源码【Spring Boot 2.7.9】:

@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
	return new StringRedisTemplate(redisConnectionFactory);
}

上述逻辑也好理解,它表示只有在当前上下文中不存在名为 "stringRedisTemplate"Bean 时,才会创建一个名为stringRedisTemplateStringRedisTemplate Bean,并将其与一个可用的 Redis 连接工厂关联起来。

StringRedisTemplateRedisTemplate 的子类,专门用于处理字符串类型的数据。

StringRedisTemplate 使用的是 StringRedisSerializer,它在存入数据时会将数据先序列化成字节数组。

默认情况下,StringRedisTemplate 采用的序列化策略有两种:

  • String 的序列化策略,
  • JDK 的序列化策略。

总结

本篇我们深入分析了 RedisAutoConfiguration 配置类的相关内容,进一步加深了对自动配置装配流程的了解。其中有关 LettuceConnectionConfigurationJedisConnectionConfiguration 这两个用于配置 Redis 连接的具体实现,笔者后面有时间再带大家详细分析一下。

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

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

相关文章

【C++基础入门】44.C++中对象模型分析(上)

一、回归本质 class 是一种特殊的 struct 在内存中 class 依旧可以看作变量的集合class 与 struct 遵循相同的内存对齐规则class 中的成员函数与成员变量是分开存放的 每个对象有独立的成员变量所有对象共享类中的成员函数值得思考的问题 下面看一个对象内存布局的代码&#x…

Go学习第十七章——Gin中间件与路由

Go web框架——Gin中间件与路由 1 单独注册中间件1.1 入门案例1.2 多个中间件1.3 中间件拦截响应1.4 中间件放行 2 全局注册中间件3 自定义参数传递4 路由分组4.1 入门案例4.2 路由分组注册中间件4.3 综合使用 5 使用内置的中间件6 中间件案例权限验证耗时统计 1 单独注册中间件…

Java项目之网络考试系统

视频教程&#xff1a; 01-创建数据库_哔哩哔哩_bilibili 源码下载&#xff1a;百度网盘 请输入提取码 准备工作 创建数据库配置IDEA后端导入前端 前言&#xff1a; 把代码掰开写进博客里&#xff0c;主要是让自己在整理笔记的过程中&#xff0c;多去思考完成这个功能的核心…

基于深度学习的单图像人群计数研究:网络设计、损失函数和监控信号

摘要 https://arxiv.org/pdf/2012.15685v2.pdf 单图像人群计数是一个具有挑战性的计算机视觉问题,在公共安全、城市规划、交通管理等领域有着广泛的应用。近年来,随着深度学习技术的发展,人群计数引起了广泛的关注并取得了巨大的成功。通过系统地回顾和总结2015年以来基于深…

rust学习——智能指针Rc

文章目录 Rc 与 ArcRcRc::clone观察引用计数的变化不可变引用一个综合例子Rc 简单总结 多线程无力的 RcArcArc 的性能损耗 总结 Rc 与 Arc Rust 所有权机制要求一个值只能有一个所有者&#xff0c;在大多数情况下&#xff0c;都没有问题&#xff0c;但是考虑以下情况&#xff1…

二维码智慧门牌管理系统升级解决方案:采集要素为智慧城市建设提供精准数据支持

文章目录 前言一、二维码智慧门牌管理系统的升级需求二、采集要素在系统升级中的应用三、消防栓、井盖等采集要素的应用 前言 随着城市化进程的加速&#xff0c;智慧城市的建设已成为未来城市发展的必然趋势。其中&#xff0c;二维码智慧门牌管理系统作为智慧城市的重要组成部…

基于Spring Boot的大学课程排课系统设计与实现

摘 要 大学课程排课是现代教育管理中重要的一环。目前&#xff0c;传统的排课方式已经无法满足日益增长的课程需求和学生个性化的诉求。因此&#xff0c;研究一种基于遗传算法的大学课程排课系统是非常必要的。本研究旨在开发一种基于SpringBoot Vue的大学课程排课系统&#x…

【Java 进阶篇】在Java Web应用中获取ServletContext对象详解

在Java Web应用开发中&#xff0c;ServletContext对象扮演着重要的角色&#xff0c;它允许你在整个Web应用程序中存储和共享数据。ServletContext对象是Servlet容器提供的一种用于管理Web应用程序的全局信息的方式。本文将详细探讨ServletContext对象的概念、用途以及如何在Jav…

算法笔记【8】-合并排序算法

文章目录 一、前言二、合并排序算法基本原理三、实现步骤四、优缺点分析 一、前言 合并排序算法通过采用分治策略和递归思想&#xff0c;实现了高效、稳定的排序功能。本文将深入探讨合并排序算法的原理、实现步骤&#xff0c;并讨论其优缺点。 二、合并排序算法基本原理 合…

AntDB数据库荣获 “2023年信创物联网优秀服务商”

日前&#xff0c;在2023世界数字经济大会暨第十三届智博会 2023京甬信创物联网产融对接会上&#xff0c;AntDB数据库再获殊荣&#xff0c;获评“2023年信创物联网优秀服务商”。 图1&#xff1a;2023年信创物联网优秀服务商颁奖现场 信创物联网是信息技术应用创新与物联网的结…

网络爬虫入门导学

一、内容组织 2、常用的python IDE工具 比较推荐以下几种&#xff1a; 其中IDLE是python自带的/默认的/常用的/入门级编写工具&#xff0c;包含交互式和文件式 适用于&#xff1a;简单直接/入门级/代码不超过300行 Sublime Text是专为程序员开发的第三方专用编程工具&#xff…

OPNET <<< Program Abort >>> Standard function stack imbalance

OPNET <<< Program Abort >>> Standard function stack imbalance OPNET 问题原因及解决办法 OPNET 问题 OPNET仿真时遇到此问题&#xff1a; <<< Program Abort >>> Standard function stack imbalance 原因及解决办法 出现此问题是因…

【逗老师的无线电】艾德克斯ITECH电源电子负载网口适配器

艾德克斯的产品还是不错的&#xff0c;但是ITECH的大部分中低端设备都不带网口&#xff0c;只带了一个串口&#xff0c;并且这个串口还是个完全非标定义的5V TTL串口&#xff0c;原装的适配器300多还只能转接成RS-232。 那么&#xff0c;这回咱们来整个骚活&#xff0c;直接给艾…

Go-Python-Java-C-LeetCode高分解法-第十二周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 我搜集到了50道精选题&#xff0c;适合速成概览大部分常用算法 突…

简单明了!网关Gateway路由配置filters实现路径重写及对应正则表达式的解析

问题背景&#xff1a; 前端需要发送一个这样的请求&#xff0c;但出现404 首先解析请求的变化&#xff1a; http://www.51xuecheng.cn/api/checkcode/pic 1.请求先打在nginx&#xff0c;www.51xuecheng.cn/api/checkcode/pic部分匹配到了之后会转发给网关进行处理变成localho…

人工智能-线性回归的从零开始实现

线性回归的从零开始实现 在了解线性回归的关键思想之后&#xff0c;我们可以开始通过代码来动手实现线性回归了。 在这一节中&#xff0c;我们将从零开始实现整个方法&#xff0c; 包括数据流水线、模型、损失函数和小批量随机梯度下降优化器。 虽然现代的深度学习框架几乎可以…

预安装win11的电脑怎么退回正版win10?

对于新购的笔记本 通常来讲预装的系统是全新安装的&#xff0c;是没有之前Windows10系统文件的&#xff0c;无法回退。 可以打开设置-----系统----恢复-----看下是否有该选项。 ------------------------------------------------------------------------------- 若是在上述…

[论文精读]How Powerful are Graph Neural Networks?

论文原文&#xff1a;[1810.00826] How Powerful are Graph Neural Networks? (arxiv.org) 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#x…

字符串固定长度自动补齐的主要方法

1 问题 输入日期例如02/03/04时&#xff0c;要求输出2002年03月04日、2004年02月03日或2004年03月04日&#xff0c;但是经过一系列处理后0会被自动处理掉&#xff0c;例如输出2002年3月4日等&#xff0c;与要求输出月、日必须是两位数不符。 2 方法 要自动补充“0”&#xff0c…

<学习笔记>从零开始自学Python-之-常用库篇(十三)内置小型数据库shelve

一、shelve简介&#xff1a; shelve是Python当中数据储存的方案&#xff0c;类似key-value数据库&#xff0c;便于保存Python对象&#xff0c;shelve只有一个open&#xff08;&#xff09;函数&#xff0c;用来打开指定的文件&#xff08;字典&#xff09;&#xff0c;会返回一…