spring-smart-di 动态切换接口源

0、背景

一般我们系统同一个功能可能会对接多个服务商,防止某个服务商的服务不可用快速切换或者收费不同需要切换,那我们一般做快速切换逻辑传统无非就是先将每个服务商实现,然后在配置点(数据库或者nacos)配置当前正在使用的服务商。然后每次执行的时候从配置点获取当前正在使用的服务商,然后去执行该服务商的业务逻辑。

比如系统接入了多个短信服务商,然后用户可以动态的切换不同的服务商,

如果让我们手写会如何实现。

  • 第一步先在某个位置(不管是nacos还是数据库)配置当前使用的服务商的对应值比如 sms.impl = "某腾短信"

  • 第二步,在代码里执行发短信的时候,手动获取该sms.impl对应的服务商的实现类,伪代码可能如下

void sendSmsTouser(Req req){// 1、获取当前使用的服务商String name = get("sms.impl");// 2、获取对应的实现类SmsService smsService = springContext.getBean(name);// 3、使用smsService执行具体业务逻辑smsService.sendMsg(req)
}

这时有一个想法就是 spring的@Autowired注解在注入的时候可以自动根据在配置点配置的实现类去注入,并且当配置变了,注入的实现类也会改变,这样就跟正常写代码一样不再需要去关注当前使用的实现类。这时spring-smart-di 的 AutowiredProxySPI 应运而生。

1、spring-smart-di

它是一个对spring@Autowired注解的扩展,能够自定义用户自己的Autowired注入逻辑,目前实现了两个功能分别是 @SmartAutowired @AutowiredProxySPI 注解,我们这里要使用的便是AutowiredProxySPI 去实现我们的动态切换逻辑。

假设对接了多个短信服务商,下面以一个快速开始案例去看看如何使用 AutowiredProxySPI 如何实现动态切换

2、快速开始

引入依赖

    <dependency><groupId>io.github.burukeyou</groupId><artifactId>spring-smart-di-all</artifactId><version>0.2.0</version></dependency>

然后在Spring配置类上标记 @EnableSmartDI 注解 启用功能

2.1 @EnvironmentProxySPI注解

@EnvironmentProxySPI代表的是一个配置点,用来配置怎么获取具体实现类的逻辑。

假设系统短信服务商存在以下两个服务商,我们需要做动态切换。 需要在接口上配置@EnvironmentProxySPI表示从环境变量配置点中获取当前使用的服务商。这里配置到属性 ${sms.impl}

@EnvironmentProxySPI("${sms.impl}")
public interface SmsService {
}@BeanAliasName("某腾短信服务")
@Component
public class ASmsService implements SmsService {
}@BeanAliasName("某移短信服务")
@Component
public class BSmsService implements SmsService {
}

2.1 配置当前使用的服务商

比如在配置文件中配置。 这里的值可以是@BeanAliasName的值,也可以是@Component的值,也可以具体的是全路径类名。

sms:impl: 某移短信服务

2.3 @AutowiredProxySPI注入使用

// 依赖注入
@AutowiredProxySPI
private SmsService smsService;

这样我们就完成了一个动态切换需求,只要我们改变配置配置属性${sms.impl}的值就会实时生效而无需重启服务,因为他注入的是一个代理对象每次执行时会先去实时获取当前使用的实现类然后才去执行调用, 并且在使用上与原先直接使用@Autowired基本毫无区别

2.4 定义不同的配置点

@EnvironmentProxySPI是用来配置环境变量相关的配置点,如果想要自定义配置比如在数据库中可实现自己的ProxySPI注解。

比如自定义DBProxySPI注解,并标记上@ProxySPI实现并指定具体配置获取逻辑实现类AnnotationProxyFactory即可。

然后DBProxySPI就可以像@EnvironmentProxySPI一样去使用了,下面是实现的伪代码

@Inherited
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ProxySPI(DbProxyFactory.class) // 指定配置获取逻辑
public @interface DBProxySPI {String value();}@Component
public class DbProxyFactory implements AnnotationProxyFactory<DBProxySPI> {@Autowiredprivate SysConfigMapper sysConfigDao;@Overridepublic Object getProxy(Class<?> targetClass,DBProxySPI spi) {// todo 根据注解从数据库获取要注入的实现类String configName = sysConfigDao.getConfig(spi.value());return springContext.getBean(configName);}
}@DBProxySPI("${sms.impl}")
public interface SmsService {
}

其他

github项目地址

maven仓库地址

还在迭代中,第一个版本主要专注于动态切换, 还需要什么好玩的功能和特征请留下你的意见感谢。 觉得有用或者能学到点什么可以star下哈哈。

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

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

相关文章

ChromeDriver全版本下载教程

确定自己的Chrome版本 step1. 打开Chrome浏览器右上角的三个点&#xff0c;再点击设置 step2. 在设置中点击“关于Chrome”&#xff0c;圈起来的红框即为当前Chrome版本&#xff0c;我的版本就是121.0.6167.185 在json中查找自己对应ChromeDriver版本下载链接 一般教程会让你…

linux条件判断之case-in-esac

之前提到的“if...then...fi”是通过比较来判断变量的&#xff0c;如果符合状态就进行某些行为动作&#xff0c;并且通过较多层次(就是elif...)的方式&#xff0c;进行多个变量的判断&#xff0c;其也可以使用case...in...esac方式进行实现 1.case...in...esac格式 case $变量…

Linux如何设计一个线程池

在设计线程池之前&#xff0c;我们可以对线程进行简单的封装这样子在线程池中就可以少一点调用接口&#xff0c;就像搭积木一样&#xff0c;一层一层的搭上去 #pragma once#include <iostream> #include <pthread.h> #include <string> #include <functi…

【树】【异或】【深度优先】【DFS时间戳】2322. 从树中删除边的最小分数

作者推荐 【二分查找】【C算法】378. 有序矩阵中第 K 小的元素 涉及知识点 树 异或 DFS时间戳 LeetCode2322. 从树中删除边的最小分数 存在一棵无向连通树&#xff0c;树中有编号从 0 到 n - 1 的 n 个节点&#xff0c; 以及 n - 1 条边。 给你一个下标从 0 开始的整数数组…

【操作系统学习笔记】文件管理1.3

【操作系统学习笔记】文件管理1.3 参考书籍: 王道考研 视频地址: Bilibili I/O 控制方式 程序直接控制方式中断驱动方式DMA 方式通道控制方式 程序直接控制方式 关键词: 轮询 完成一次读/写操作的流程 CPU 向控制器发出读指令。于是设备启动&#xff0c;并且状态寄存器设…

2021 年 12 月青少年软编等考 C 语言一级真题解析

目录 T1. 输出整数部分思路分析 T2. 疫情集中隔离思路分析 T3. 字符判断思路分析 T4. 统计数思路分析 T5. 最大质因子思路分析 T1. 输出整数部分 输入一个双精度浮点数 f f f&#xff0c;输出其整数部分。 时间限制&#xff1a;1 s 内存限制&#xff1a;64 MB 输入 一个双精…

C++惯用法之RAII思想: 资源管理

C编程技巧专栏&#xff1a;http://t.csdnimg.cn/eolY7 目录 1.概述 2.RAII的应用 2.1.智能指针 2.2.文件句柄管理 2.3.互斥锁 3.注意事项 3.1.禁止复制 3.2.对底层资源使用引用计数法 3.3.复制底部资源(深拷贝)或者转移资源管理权(移动语义) 4.RAII的优势和挑战 5.总…

探索Pandas:数据处理与分析的利剑

在这篇文章中&#xff0c;我们将深入探讨Pandas库&#xff0c;这是一个开源的Python库&#xff0c;专为数据分析和处理而设计。Pandas提供了高效的DataFrame对象&#xff0c;使得数据清洗、分析变得简单易行。通过本篇文章&#xff0c;我们不仅会了解Pandas的核心功能&#xff…

MATLAB:Image Processing Toolbox工具箱入门实战

目录 1.基本图像导入、处理和导出 2.实战项目一&#xff1a;利用imfindcircles()函数检测和测量图像中的圆形目标 1.基本图像导入、处理和导出 Basic Image Import, Processing, and Export- MATLAB & SimulinkThis example shows how to read an image into the worksp…

linux系统iptables的操作

iptables操作 安装参数解释参数使用iptables语法示例规则匹配条件通用匹配&#xff08;协议&#xff09;&#xff0c;可以独立使用通过端口规则匹配:通过ip地址修改规则: icmp类型匹配扩展匹配指定ip范围指定多端口范围MAC地址匹配通过网卡接口保存和删除规则本地端口转发 网络…

前端Vue篇之Vue 3.0 中的 Vue Composition API?Composition API与React Hook很像,区别是什么

目录 Vue 3.0 中的 Vue Composition API&#xff1f;Composition API与React Hook很像&#xff0c;区别是什么1. 实现原理2. 调用方式和性能3. 生态和社区 Vue 3.0 中的 Vue Composition API&#xff1f; 在Vue 3中&#xff0c;引入了Composition API来解决Vue 2中Options API…

Java集合框架-Collection和Map

文章目录 Collection-单列集合特点ListArrayListLinkedListVecter SetHashSetTreeSet Map-键值对集合特点Map常用APIput添加细节remove Map的三种遍历方式1.通过键找值2.通过"键值对"3.Lambda表达式foreach源码 HashMap需求 为什么要使用泛型 泛型的优点1.集合中存储…

#QT(智能家居界面-布局)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 水平布局&#xff0c;垂直布局&#xff0c;栅格布局&#xff08;弹簧&#xff09; 界面自动调整 3.记录 注意弹簧不是拖拽拉长&#xff0c;而是使用栅格布局 运行发现窗口放大缩小可以自动调整 如果想要重新布局&#xff0c;需…

Feign失败降级逻辑

一&#xff0c;为什么要编写失败降级逻辑 业务失败后&#xff0c;不能直接报错&#xff0c;而应该返回用户一个提示或者默认结果 二&#xff0c;实现步骤 1&#xff0c;自定义类实现FallbackFactory接口 import feign.hystrix.FallbackFactory; import lombok.extern.slf4j.Sl…

LCR 095. 最长公共子序列【leetcode】/动态规划

LCR 095. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某…

【PHP趣味技术】分分钟教会你轻松采集PDF文本内容 《重庆话真的太吃皮老!》

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

备忘 clang diagnostic 类的应用示例 ubuntu 22.04

系统的ncurses环境有些问题 通过源码安装了ncurses6.3后&#xff0c;才可以在 llvmort-18.1.rc4中编译通过示例&#xff1a; 1&#xff0c;折腾环境 ncurses-6.3$ ./configure ncurses-6.3$ make -j ncurses-6.3$ sudo make install sudo apt install libtinfo5 sudo…

C判断操作系统、编译器类型、编译器版本及编译位数

1. 操作系统 #ifdef __linux__// Linux #elif defined(_WIN32) || defined(_WIN64)// Windows #else// 其他 #endif2. 编译器类型及版本 #ifdef __GNUC__// 使用了GCC编译器#if __GNUC__ > 7// GCC版本大于等于7#else// GCC版本小于7#endif #elif defined(_MSC_VER)// …

使用Visual Studio 2022 创建lib和dll并使用

概述&#xff1a;对于一个经常写javaWeb的人来说,使用Visual Studio似乎没什么必要&#xff0c;但是对于使用ffi的人来说&#xff0c;使用c或c编译器&#xff0c;似乎是必不可少的&#xff0c;下面我将讲述如何用Visual Studio 2022 来创建lib和dll&#xff0c;并使用。 静态库…

springboot/ssm华为数码商城交易平台Java数码手机购物系统web

springboot/ssm华为数码商城交易平台Java数码手机购物系统web 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;…