Spring Boot 3 配置 Redis 兼容单例和集群
配置项
Spring Boot 3.x 的 redis 配置和 Spring Boot 2.x 是不一样的, 路径多了一个data
spring:...data:redis:host: @redis.host@port: @redis.port@password: @redis.password@database: @redis.database@
兼容单例和集群的配置
开发时一般用一个Redis单例就足够, 测试和生产环境再换成集群, 但是在application.yml中默认的 Redis 单例和集群配置格式是不同的, 如果要用同一套格式兼容两种配置, 需要自定义 RedisConnectionFactory 这个bean的初始化.
@Configuration
public class RedisConfig {@Value("${spring.data.redis.host}")public String host;@Value("${spring.data.redis.port}")public int port;@Value("${spring.data.redis.password}")public String password;@Value("${spring.data.redis.database}")public int database;@Beanpublic RedisTemplate<String, String> redisStringTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);redisTemplate.setDefaultSerializer(new StringRedisSerializer());return redisTemplate;}@Beanpublic RedisTemplate<String, byte[]> redisBytesTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, byte[]> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);RedisSerializer<String> redisKeySerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(redisKeySerializer);redisTemplate.setHashKeySerializer(redisKeySerializer);redisTemplate.setValueSerializer(RedisSerializer.byteArray());redisTemplate.setHashValueSerializer(RedisSerializer.byteArray());return redisTemplate;}@Beanpublic RedisConnectionFactory lettuceConnectionFactory() {if (host.contains(",")) {RedisClusterConfiguration config = new RedisClusterConfiguration(Arrays.asList(host.split(",")));config.setMaxRedirects(3);if (password != null && !password.isEmpty()) {config.setPassword(RedisPassword.of(password));}LettuceConnectionFactory factory = new LettuceConnectionFactory(config);factory.afterPropertiesSet();return factory;} else {RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();config.setHostName(host);config.setPort(port);config.setDatabase(database);if (password != null && !password.isEmpty()) {config.setPassword(RedisPassword.of(password));}LettuceConnectionFactory factory = new LettuceConnectionFactory(config);factory.afterPropertiesSet();return factory;}}}
这样, 当配置改为集群时, 只需要修改 spring.data.redis.host 的内容为 1.1.1.1:6379,1.1.1.2:6379,1.1.1.3:6379
这样的格式就可以了.
使用 Byte 作为值存储
ByteUtil.java
public class ByteUtil {public static byte[] toByte(String str) {if (str == null) return null;return str.getBytes();}public static byte[][] toByte(String[] strs) {if (strs == null) return null;byte[][] arr = new byte[strs.length][];for (int i = 0; i < strs.length; i++) {arr[i] = strs[i].getBytes();}return arr;}public static String toString(byte[] bytes) {return bytes == null ? null : new String(bytes);}public static Set<String> toString(Set<byte[]> byteset) {if (byteset == null) return null;return byteset.stream().map(String::new).collect(Collectors.toSet());}public static List<String> toStrings(List<byte[]> byteslist) {if (byteslist == null) return null;return byteslist.stream().map(String::new).collect(Collectors.toList());}public static byte[] toByte(int x) {ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);buffer.putInt(x);return buffer.array();}public static int toInteger(byte[] bytes) {ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);buffer.put(bytes);buffer.flip();//need flipreturn buffer.getInt();}public static byte[] toByte(long x) {ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);buffer.putLong(x);return buffer.array();}public static long toLong(byte[] bytes) {ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);buffer.put(bytes);buffer.flip();//need flipreturn buffer.getLong();}public static byte[] toByte(Object object) {if (object == null) return null;try (ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos)) {oos.writeObject(object);return baos.toByteArray();} catch (IOException e) {throw new RuntimeException(e);}}public static <T> List<T> toObjs(List<byte[]> byteslist) {if (byteslist == null) return null;List<T> list = new ArrayList<>();for (byte[] bytes : byteslist) {T t = toObj(bytes);list.add(t);}return list;}@SuppressWarnings("unchecked")public static <T> T toObj(byte[] bytes) {if (bytes == null || bytes.length < 8) return null;try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);ObjectInputStream ois = new ObjectInputStream(bais)) {return (T)ois.readObject();} catch (IOException|ClassNotFoundException e) {throw new RuntimeException(e);}}
}
在服务中的调用方式
@Autowired
private RedisTemplate<String, byte[]> redisBytesTemplate;@Override
public Boolean hasKey(String key) {return redisBytesTemplate.hasKey(key);
}@Override
public Boolean hashHasKey(String key, String field) {return redisBytesTemplate.opsForHash().hasKey(key,field);
}@Override
public Integer hashGetInt(String key, String field) {HashOperations<String, String, byte[]> opsForHash = redisBytesTemplate.opsForHash();byte[] bytes = opsForHash.get(key, field);return bytes == null? null : ByteUtil.toInteger(bytes);
}@Override
public void hashSetInt(String key, String field, int value) {HashOperations<String, String, byte[]> opsForHash = redisBytesTemplate.opsForHash();opsForHash.put(key, field, ByteUtil.toByte(value));
}@Override
public <T> T hashGetObj(String key, String field) {HashOperations<String, String, byte[]> opsForHash = redisBytesTemplate.opsForHash();return ByteUtil.toObj(opsForHash.get(key, field));
}@Override
public <T> void hashSetObj(String key, String field, T value) {HashOperations<String, String, byte[]> opsForHash = redisBytesTemplate.opsForHash();opsForHash.put(key, field, ByteUtil.toByte(value));
}/*** @param timeout seconds to block*/
@Override
public <T> T bLPopObj(int timeout, String key) {ListOperations<String, byte[]> opsForList = redisBytesTemplate.opsForList();byte[] bytes = opsForList.leftPop(key, timeout, TimeUnit.SECONDS);return ByteUtil.toObj(bytes);
}@Override
public <T> Long rPush(String key, T value) {ListOperations<String, byte[]> opsForList = redisBytesTemplate.opsForList();return opsForList.rightPush(key, ByteUtil.toByte(value));
}
参考
- https://vincentbogousslavsky.com/post/configuration-for-spring-data-redis-reactive-for-connecting
创建 RedisClusterConfiguration - https://blog.csdn.net/weixin_67601403/article/details/129706748
创建 RedisConnectionFactory lettuceConnectionFactory - https://cloud.tencent.com/developer/article/2371793
默认的级联配置方式
相关文章:
Spring Boot 3 配置 Redis 兼容单例和集群
配置项 Spring Boot 3.x 的 redis 配置和 Spring Boot 2.x 是不一样的, 路径多了一个data spring:...data:redis:host: redis.hostport: redis.portpassword: redis.passworddatabase: redis.database兼容单例和集群的配置 开发时一般用一个Redis单例就足够, 测试和生产环境…...
unsat钱包签名算法解析
unsat钱包签名算法解析 在数字货币领域,安全性是至关重要的,而签名算法则是确保交易和信息不可伪造的基础。本文将深入解析 unsat 钱包中使用的签名算法,重点关注如何生成和验证消息签名。 1. 签名算法概述 unsat 钱包使用 ECDSAÿ…...
mysql删除唯一索引
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...
学习之面试题:偏函数
偏函数(Partial Function)是 Python 中的一个实用工具,通常用于函数式编程中,可以固定一个函数的部分参数,从而生成一个新的函数。偏函数在 Python 中通常通过 functools.partial 实现。在面试中,考察偏函数…...

面试技术点
Java 一、jvm模块 jvm是什么? 是一用用于计算设备的规范,虚构出来的计算机,在计算机上仿真模拟各种计算机功能来实现 jvm 作用是什么? java中所有类必须装载jvm中才能运行,这个装载工作有jvm装载器完成,.class类型文件能在jvm虚拟器中运行,但不能直接在系统中运行,需要…...

基础sql
在执行删除操作之前,建议先运行一个 SELECT 查询来确认你要删除的记录。这可以帮助你避免误删数据。 删除字段id默认值为空字符串的所有数据 delete from users where id ; 删除字段id默认值为null的所有数据 delete from users where id is null; 删除字段upd…...

Jenkins整合Docker实现CICD自动化部署(若依项目)
前期准备 提前准备好jenkins环境 并且jenkins能使用docker命令,并且已经配置好了jdk、node、maven环境,我之前写了安装jenkins的博客,里面讲得比较详细,推荐用我这种方式安装 docker安装jenkins,并配置jdk、node和m…...
kali chrome 安装 hackbar
HackBar 是一个用于在 Kali Linux 中快速测试 SQL 注入和 XSS 漏洞的 Chrome 扩展程序。以下是如何在 Kali Linux 上安装 HackBar 的步骤: 首先,你需要确保你的系统已经安装了 Google Chrome 或 Chromium。如果没有安装,你可以使用以下命令安…...

一文了解 Linux 系统的文件权限管理
文章目录 引入Linux文件权限模型查看文件权限权限信息解析修改文件权限符号模式八进制数字模式 引入 在Linux操作系统中,我们想查看我们对文件拥有哪些权限时,可以在终端键入ls -l或ll命令,终端会输出当前路径下的文件信息,如文件…...

Spark:DataFrame介绍及使用
1. DataFrame详解 DataFrame是基于RDD进行封装的结构化数据类型,增加了schema元数据,最终DataFrame类型在计算时,还是转为rdd计算。DataFrame的结构化数据有Row(行数据)和schema元数据构成。 Row 类型 表示一行数据 …...

Linux系统:本机(物理主机)访问不了虚拟机中的apache服务问题的解决方案
学习目标: 提示:本文主要讲述-本机(物理主机)访问不了虚拟机中的apache服务情况下的解决方案 Linux系统:Ubuntu 23.04; 文中提到的“本机”:代表,宿主机,物理主机; 首先,…...

望繁信科技成功签约国显科技 流程挖掘助力制造业智造未来
近日,上海望繁信科技有限公司(简称“望繁信科技”)成功与深圳市国显科技有限公司(简称“国显科技”)达成合作。国显科技作为全球领先的TFT-LCD液晶显示及Mini/Micro LED显示产品供应商,致力于为笔记本、手机…...

枚举在Java体系中的作用
1. 枚举 枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式: //用public static final修饰常量 public static final int RED 1; public static final int GREEN 2; public static f…...

『气泡水』Web官网 案例赏析
前言 Schweppes,作为一家享誉全球的气泡水品牌,致力于与年轻消费者建立更紧密的联系,并提升品牌影响力。为此,其打造了一个充满创意和高度互动性的官网,利用前端技术和动画效果,将产品特性与用户浏览体验完…...

【前端】制作一个简单的网页(2)
单标签组成的元素 这类标签不需要内容产生效果,通常表示对网页的某种行为,它们不用标记任何内容,开始即是结束。 比如,<hr>标签的作用是在网页中添加一条分割线,它仅包含开始标签,是一个单标签元素。…...

OpenAI Canvas:提升编程与写作效率的全新工作界面
随着人工智能技术的飞速发展,大语言模型(LLM)不仅限于生成文本,还能逐步扩展至编程、设计等任务的支持。近期,OpenAI 推出了一个名为 Canvas 的全新功能,专门用于协助用户进行编程和写作。这一功能与 Claud…...

将SpringBoot的Maven项目打成jar包和war包
先需要明确的是,该项目打包的形态是可执行的jar包,还是在tomcat下运行的war包。 springboot自带的maven打包 1.创建一个springboot web项目 1.api控制层HelloWorld.java RestController RequestMapping("/hello") public class HelloWorld …...
【Iceberg分析】Spark与Iceberg集成之常用存储过程
文章目录 Spark与Iceberg集成之常用存储过程调用语法调用样例表快照管理快照回滚根据snapshotid进行回滚根据timestamp进行回滚 设置表当前生效的快照 表元数据管理设置快照过期时间清除孤岛文件重写数据文件运用参数示例optionsGeneral OptionsOptions for sort strategyOptio…...

[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。
[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。 最近在开发的时候,发现一个依赖事件来刷新渲染的控件会导致程序很容易异常和崩溃。 当程序在运行的时候,其实软件本身的负载并不高,所以…...

云上考场小程序+ssm论文源码调试讲解
2 关键技术简介 2.1 微信小程序 微信小程序,简称小程序,英文名Mini Program,是一种全新的连接用户与服务的方式,可以快速访问、快速传播,并具有良好的使用体验。 小程序的主要开发语言是JavaScript,它与…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...

论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...