👉 这是一个或许对你有用的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:
《项目实战(视频)》:从书中学,往事上“练”
《互联网高频面试题》:面朝简历学习,春暖花开
《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题
《精进 Java 学习指南》:系统学习,互联网主流技术栈
《必读 Java 源码专栏》:知其然,知其所以然

👉这是一个或许对你有用的开源项目
国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。
功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号、CRM 等等功能:
Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro
Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud
视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本
来源:juejin.cn/post/
7342279484487270450

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 应运而生。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro
视频教程:https://doc.iocoder.cn/video/
1、spring-smart-di
它是一个对spring @Autowired注解的扩展,能够自定义用户自己的Autowired注入逻辑,目前实现了两个功能分别是 @SmartAutowired 和 @AutowiredProxySPI 注解,我们这里要使用的便是AutowiredProxySPI 去实现我们的动态切换逻辑。
假设对接了多个短信服务商,下面以一个快速开始案例去看看如何使用 AutowiredProxySPI 如何实现动态切换
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud
视频教程:https://doc.iocoder.cn/video/
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.2 配置当前使用的服务商
比如在配置文件中配置。这里的值可以是@BeanAliasName的值,也可以是@Component的值,也可以具体的是全路径类名。
sms:
impl: 某移短信服务
2.3 @AutowiredProxySPI注入使用
然后我们只需要像使用@Autowired注解一样去使用 @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> {
@Autowired
private SysConfigMapper sysConfigDao;
@Override
public Object getProxy(Class<?> targetClass,DBProxySPI spi) {
// todo 根据注解从数据库获取要注入的实现类
String configName = sysConfigDao.getConfig(spi.value());
return springContext.getBean(configName);
}
}
@DBProxySPI("${sms.impl}")
public interface SmsService {
}
其他
GitHub项目地址
https://github.com/burukeYou/spring-smart-di
Maven仓库地址
https://central.sonatype.com/artifact/io.github.burukeyou/spring-smart-di-all
还在迭代中,第一个版本主要专注于动态切换, 还需要什么好玩的功能和特征请留下你的意见感谢。觉得有用或者能学到点什么可以star下哈哈。
欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,“长按”或“扫描”下方二维码噢:

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。





文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
2089



被折叠的 条评论
为什么被折叠?



