Redis 多数据源 Spring Boot 实现

1.前言

本文为大家提供一个 redis 配置多数据源的实现方案,在实际项目中遇到,分享给大家。后续如果有时间会写一个升级版本,升级方向在第5点。

2.git 示例地址

git 仓库地址:https://github.com/huajiexiewenfeng/redis-multi-spring/tree/master/redis-multi-spring

不同的 spring boot 版本,对应的写法可能有小的区别,但思想不变

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.0.1.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.0.1.RELEASE</version></dependency>

3.需求分析

对于 redis 配置多数据源的需求,至少可以分析出以下需求和实现点

  • 在同一个项目中,可以操作多个 redis 服务实例
    • 通过不同的 redisTemplate 可以调用不同的 redis 实例服务
    • Spring @Qualifier 来实现
  • 如果原项目已经引入spring-redis,不能影响 Spring boot 里面默认配置的 redis 自动配置服务
    • org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
    • 要与 RedisAutoConfiguration 里面的 spring bean 完全隔离
  • 因为 host port 等重要参数都在 RedisConnectionFactory 中,所以 RedisConnectionFactory 我们需要配置多个

4.代码实现

不能影响 Spring boot 里面默认配置的 redis 自动配置服务,以 JedisConnectionConfiguration 自动配置实现为例。

  • @ConditionalOnMissingBean({RedisConnectionFactory.class}) 表示如果 spring 容器中存在 RedisConnectionFactory 的具体实现,那么该自动配置 bean 方法不会生效;所以在我们后面的实现中要避免这种写法。

请添加图片描述

4.1 第一个 RedisTemplate 配置

需要特别注意的是,在某些 spring boot 版本里面,如果不写或者少写该配置,使用过程中会报错

  • template.afterPropertiesSet();
  • jedisConnectionFactory.afterPropertiesSet();

为了避免 getJedisConnectionFactory 方法影响 spring redis 默认配置,不能增加 @Bean 注解的方式,用 name 属性区分也不行。

4.1.1 RedisOneProperties Properties 类
@Configuration
@ConfigurationProperties(prefix = "multi.redis.one")
@Data
public class RedisOneProperties {private String host;private int port;private int database = 1;private String password;}
4.1.2 RedisMultiConfiguration 具体配置
    @Autowiredprivate RedisOneProperties properties;// 第一个Redis服务器的配置@Bean("oneRedisTemplate")public RedisTemplate<String, Object> oneRedisTemplate() {JedisConnectionFactory jedisConnectionFactory = this.getJedisConnectionFactory();RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置key的序列化方式StringRedisSerializer keySerializer = new StringRedisSerializer();template.setConnectionFactory(jedisConnectionFactory);template.setKeySerializer(keySerializer);// 设置value的序列化方式Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是无论什么都可以序列化om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 启用DefaultTyping,方便我们反序列化时知道对象的类型om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);valueSerializer.setObjectMapper(om);template.setValueSerializer(valueSerializer);// 设置Hash的key和value序列化方式template.setHashKeySerializer(keySerializer);template.setHashValueSerializer(valueSerializer);// 设置value的泛型类型,这样在存取的时候才会序列化和反序列化成设置的对象类型// 注意:这里只是设置了value的泛型,key还是String类型template.afterPropertiesSet();return template;}private JedisConnectionFactory getJedisConnectionFactory() {JedisPoolConfig poolConfig = new JedisPoolConfig();// 设置连接池参数,例如最大连接数、最大空闲连接数等poolConfig.setMaxTotal(100);poolConfig.setMaxIdle(30);poolConfig.setMinIdle(10);JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);jedisConnectionFactory.setHostName(properties.getHost());jedisConnectionFactory.setPort(properties.getPort());jedisConnectionFactory.setDatabase(properties.getDatabase());jedisConnectionFactory.setPassword(properties.getPassword());jedisConnectionFactory.afterPropertiesSet();return jedisConnectionFactory;}

4.2 第二个 RedisTemplate 配置

以此类推

4.2.1 RedisTwoProperties Properties 类
@Configuration
@ConfigurationProperties(prefix = "multi.redis.two")
@Data
public class RedisTwoProperties {private String host;private int port;private int database = 1;private String password;}
4.2.2 RedisMultiConfiguration 具体配置
    @Autowiredprivate RedisTwoProperties propertiesTwo;@Bean("twoRedisTemplate")public RedisTemplate<String, Object> twoRedisTemplate() {JedisConnectionFactory jedisConnectionFactory = this.getJedisConnectionFactoryTwo();RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置key的序列化方式StringRedisSerializer keySerializer = new StringRedisSerializer();template.setConnectionFactory(jedisConnectionFactory);template.setKeySerializer(keySerializer);// 设置value的序列化方式Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是无论什么都可以序列化om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 启用DefaultTyping,方便我们反序列化时知道对象的类型om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);valueSerializer.setObjectMapper(om);template.setValueSerializer(valueSerializer);// 设置Hash的key和value序列化方式template.setHashKeySerializer(keySerializer);template.setHashValueSerializer(valueSerializer);// 设置value的泛型类型,这样在存取的时候才会序列化和反序列化成设置的对象类型// 注意:这里只是设置了value的泛型,key还是String类型template.afterPropertiesSet();return template;}private JedisConnectionFactory getJedisConnectionFactoryTwo() {JedisPoolConfig poolConfig = new JedisPoolConfig();// 设置连接池参数,例如最大连接数、最大空闲连接数等poolConfig.setMaxTotal(100);poolConfig.setMaxIdle(30);poolConfig.setMinIdle(10);JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);jedisConnectionFactory.setHostName(propertiesTwo.getHost());jedisConnectionFactory.setPort(propertiesTwo.getPort());jedisConnectionFactory.setDatabase(propertiesTwo.getDatabase());jedisConnectionFactory.setPassword(propertiesTwo.getPassword());jedisConnectionFactory.afterPropertiesSet();return jedisConnectionFactory;}

4.3 application.properties 配置文件

spring.application.name=${APPLICATION_NAME:redis-multiple}
server.port=${SERVER_PORT:22216}# spring 默认配置
spring.redis.database=${REDIS_DB_INDEX:1}
spring.redis.flushdb=${REDIS_FLUSHDB:false}
spring.redis.host=${REDIS_HOST:127.0.0.1}
spring.redis.port=${REDIS_PORT:6379}
spring.redis.password=123456#第一个 redis 实例配置
multi.redis.one.database=${REDIS_DB_INDEX:2}
multi.redis.one.flushdb=${REDIS_FLUSHDB:false}
multi.redis.one.host=${REDIS_HOST:127.0.0.1}
multi.redis.one.port=${REDIS_PORT:6379}
multi.redis.one.password=123456#第二个 redis 实例配置
multi.redis.two.database=${REDIS_DB_INDEX:3}
multi.redis.two.flushdb=${REDIS_FLUSHDB:false}
multi.redis.two.host=${REDIS_HOST:127.0.0.1}
multi.redis.two.port=${REDIS_PORT:6379}
multi.redis.two.password=123456

4.4 测试 Demo

@RestController
public class TestController {@Autowiredprivate RedisTemplate<String,String> redisTemplate;@Autowired@Qualifier("oneRedisTemplate")private RedisTemplate<String, Object> redisTemplateOne;@Autowired@Qualifier("twoRedisTemplate")private RedisTemplate<String, Object> redisTemplateTwo;@GetMapping("/test/redis/add")public void profileDetails() {redisTemplate.opsForValue().set("test1", "1");redisTemplateOne.opsForValue().set("test2", 2);redisTemplateTwo.opsForValue().set("test3", 3);}}

浏览器输入

http://127.0.0.1:22216/test/redis/add

执行结果如下:

db1

请添加图片描述

db2
请添加图片描述

db3

请添加图片描述

5.版本升级想法

1.不需要每一个配置都写一个 Properties 类

2.不需要每一个配置都写一个 RedisTemplate 配置

    @Bean("oneRedisTemplate")public RedisTemplate<String, Object> oneRedisTemplate() {...}@Bean("twoRedisTemplate")public RedisTemplate<String, Object> twoRedisTemplate() {...}

3.使用方法可以与 properties 里面的配置直接对应,比如 oneRedisTemplate

    @Autowired@Qualifier("oneRedisTemplate")private RedisTemplate<String, Object> redisTemplateOne;

对应 application.properties 中的 multi.redis.one 前缀

multi.redis.one.database=${REDIS_DB_INDEX:2}
multi.redis.one.flushdb=${REDIS_FLUSHDB:false}
multi.redis.one.host=${REDIS_HOST:127.0.0.1}
multi.redis.one.port=${REDIS_PORT:6379}
multi.redis.one.password=123456

如果有时间,会在下篇文章中实现。

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

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

相关文章

【解码现代 C++】:实现自己的智能 【String 类】

目录 1. 经典的String类问题 1.1 构造函数 小李的理解 1.2 析构函数 小李的理解 1.3 测试函数 小李的理解 1.4 需要记住的知识点 2. 浅拷贝 2.1 什么是浅拷贝 小李的理解 2.2 需要记住的知识点 3. 深拷贝 3.1 传统版写法的String类 3.1.1 拷贝构造函数 小李的理…

共享门店模式:实体门店合伙制的解决方案

在当今这个快速迭代的商业时代&#xff0c;共享门店模式以其独到的商业智慧和灵活的运营策略&#xff0c;正逐步成为推动行业变革的重要力量。它巧妙地融合了共享经济的前沿理念与线下门店的实体优势&#xff0c;开辟了一条资源高效整合与价值深度挖掘的新路径。 共享门店模式…

MySQL学习(8):约束

1.什么是约束 约束是作用于表中字段上的规则&#xff0c;以限制表中数据&#xff0c;保证数据的正确性、有效性、完整性 约束分为以下几种&#xff1a; not null非空约束限制该字段的数据不能为nullunique唯一约束保证该字段的所有数据都是唯一、不重复的primary key主键约束…

微信小程序毕业设计-走失人员的报备平台系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

Docker 安装迅雷NAS

一、前言 在本文之前&#xff0c;博主在家用服务器 CentOS 上使用的下载方案是 Aria2 和其前端面板 Ariang. 所下载的资源大多数是 BT 资源&#xff0c;奈何 Aria2 对 BT 资源的下载速度实在堪忧&#xff0c;配置 BT 服务器效果不佳且费时。每次都将 BT 资源云添加至迅雷云盘&…

Github与本地仓库建立链接、Git命令(或使用Github桌面应用)

一、Git命令&#xff08;不嫌麻烦可以使用Github桌面应用&#xff09; git clone [] cd [] git branch -vv #查看本地对应远程的分支对应关系 git branch -a #查看本地和远程所有分支 git checkout -b [hongyuan] #以当前的本地分支作为基础新建一个【】分支,命名为h…

windows内置的hyper-v虚拟机的屏幕分辨率很低,怎么办?

# windows内置的hyper-v虚拟机的屏幕分辨率很低&#xff0c;怎么办&#xff1f; 只能这么大了&#xff0c;全屏也只是把字体拉伸而已。 不得不说&#xff0c;这个hyper-v做的很烂。 直接复制粘贴也做不到。 但有一个办法可以破解。 远程桌面。 我们可以在外面的windows系统&…

python解析Linux top 系统信息并生成动态图表(pandas和matplotlib)

文章目录 0. 引言1. 功能2.使用步骤3. 程序架构流程图结构图 4. 数据解析模块5. 图表绘制模块6. 主程序入口7. 总结8. 附录完整代码 0. 引言 在性能调优和系统监控中&#xff0c;top 命令是一种重要工具&#xff0c;提供了实时的系统状态信息&#xff0c;如 CPU 使用率、内存使…

0/1背包问题总结

文章目录 &#x1f347;什么是0/1背包问题&#xff1f;&#x1f348;例题&#x1f349;1.分割等和子集&#x1f349;2.目标和&#x1f349;3.最后一块石头的重量Ⅱ &#x1f34a;总结 博客主页&#xff1a;lyyyyrics &#x1f347;什么是0/1背包问题&#xff1f; 0/1背包问题是…

CFS三层内网渗透——第二层内网打点并拿下第三层内网(三)

目录 八哥cms的后台历史漏洞 配置socks代理 ​以我的kali为例,手动添加 socks配置好了&#xff0c;直接sqlmap跑 ​登录进后台 蚁剑配置socks代理 ​ 测试连接 ​编辑 成功上线 上传正向后门 生成正向后门 上传后门 ​内网信息收集 ​进入目标二内网机器&#xf…

小程序分包加载、独立分包、分包预加载等

一、小程序分包加载 小程序的代码通常是由许多页面、组件以及资源等组成&#xff0c;随着小程序功能的增加&#xff0c;代码量也会逐渐增加&#xff0c; 体积过大就会导致用户打开速度变慢&#xff0c;影响用户的使用体验。分包加载是一种小程序优化技术。将小程序不同功能的代…

【微信小程序开发实战项目】——花店微信小程序实战项目(4)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Nginx的安装与配置 —— Linux系统

一、Nginx 简介 1.1 什么是 Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务…

Linux系统部署MongoDB开源文档型数据库并实现无公网IP远程访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&am…

现代农业利器:土壤检测仪器的应用与未来

在现代农业发展的浪潮中&#xff0c;土壤检测仪器以其精准、高效的特点&#xff0c;成为了农业生产的得力助手。这些看似不起眼的设备&#xff0c;实际上在保障农产品质量、提高农业生产效率方面发挥着举足轻重的作用。 一、土壤检测仪器&#xff1a;现代农业的“眼睛” 土壤检…

记录第一次写脚本

使用csh语言&#xff0c;Linux系统操作的 写和执行csh&#xff08;C Shell&#xff09;脚本不需要额外的软件&#xff0c;只需要一个支持csh的终端环境。 1.检查是否安装了C Shell 在终端terminal运行以下命令 which csh 如果返回路径&#xff0c;比如/bin/csh&#xff0c…

SpringBoot 启动流程六

SpringBoot启动流程六 这句话是创建一个上下文对象 就是最终返回的那个上下文 我们这个creatApplicationContext方法 是调用的这个方法 传入一个类型 我们通过打断点的方式 就可以看到context里面的东西 加载容器对象 当我们把依赖改成starter-web时 这个容器对象会进行…

STM32-HAL-FATFS(文件系统)(没做完,stm32f103zet6(有大佬的可以在评论区说一下次板子为什么挂载失败了))

1STM32Cube配置 1-1配置时钟 1-2配置调试端口 1-3配置uart 1-4配置SDIO&#xff08;注意参数&#xff09;&#xff08;其中他的初始化的异常函数给注释&#xff0c;SD卡文件写了&#xff09; 配置了还要打开中断和DMA可在我的其他文章中看一样的 1-5配置FatFs (只改了图选中…

QT c++函数模板与类模板的使用

QT c类模板的使用 #pragma once#include <QtWidgets/QMainWindow> #include "ui_QtWidgetsApplication5.h"class QtWidgetsApplication5 : public QMainWindow {Q_OBJECTpublic:QtWidgetsApplication5(QWidget *parent nullptr);~QtWidgetsApplication5();te…

Arthas实战(4)- 线程死锁问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段线程死锁的代码&#xff1a; GetMapping("/threadLock") public void threadLock() {Thread thread1 new Thread(() -> {synchronized (resource1) {System.out.println(Thread.currentThread().g…