AI在线 AI在线

Spring-Smart-DI 动态切换实现类,很不错!

在系统开发的实际场景中,我们常常会碰到这样一类需求:同一个功能需要对接多个服务提供商。 这么做主要基于两个重要原因。 其一,为了规避某个服务商的服务出现不可用的风险,以便在出现问题时能够迅速切换到其他服务商,确保系统的稳定性和业务的连续性;其二,不同服务商的收费标准存在差异,从成本控制的角度出发,需要根据实际情况进行灵活切换。

在系统开发的实际场景中,我们常常会碰到这样一类需求:同一个功能需要对接多个服务提供商。这么做主要基于两个重要原因。其一,为了规避某个服务商的服务出现不可用的风险,以便在出现问题时能够迅速切换到其他服务商,确保系统的稳定性和业务的连续性;其二,不同服务商的收费标准存在差异,从成本控制的角度出发,需要根据实际情况进行灵活切换。

传统的快速切换逻辑实现方法是,先为每个服务商编写对应的实现类,然后在配置点(这个配置点可以是数据库,也可以是像 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-smart-di 是对 Spring @Autowired 注解的一次创新性扩展,它为用户提供了自定义 Autowired 注入逻辑的能力。目前,它实现了两个非常重要的注解:@SmartAutowired 和 @AutowiredProxySPI。在本文中,我们将重点聚焦于如何使用 AutowiredProxySPI 来实现动态切换服务提供商的功能。

假设我们的系统对接了多个短信服务商,下面我们通过一个快速上手的案例,详细了解如何使用 AutowiredProxySPI 来实现动态切换。

2、快速开始

2.1 引入依赖

首先,我们需要在项目中引入 spring-smart-di 的依赖。在 Maven 项目的 pom.xml 文件中添加以下依赖代码:

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

2.2 启用功能

在 Spring 配置类上标记 @EnableSmartDI 注解,以此来启用 spring-smart-di 的强大功能。

2.3 @EnvironmentProxySPI 注解的使用

@EnvironmentProxySPI 注解代表着一个配置点,其主要作用是配置如何获取具体实现类的逻辑。

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

复制
@EnvironmentProxySPI("${sms.impl}")
publicinterface SmsService {
}

// 给实现类定义别名
@BeanAliasName("某腾短信服务")
@Component
publicclass ASmsService implements SmsService {
}

@BeanAliasName("某移短信服务")
@Component
publicclass BSmsService implements SmsService {
}

2.4 配置当前使用的服务商

我们可以在配置文件中配置当前使用的服务商。配置的值可以是 @BeanAliasName 注解指定的值,也可以是 @Component 注解指定的值,还可以是具体的全路径类名。

复制
sms:
  impl: 某移短信服务

2.5 @AutowiredProxySPI 注入使用

接下来,我们只需要像使用 @Autowired 注解一样使用 @AutowiredProxySPI 注解即可。

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

通过以上步骤,我们就成功完成了动态切换服务提供商的需求。只要我们改变配置属性 ${sms.impl} 的值,系统就会实时生效,而无需重启服务。这是因为 @AutowiredProxySPI 注入的是一个代理对象,每次执行时会先实时获取当前使用的实现类,然后再执行调用操作。并且,在使用上与直接使用 @Autowired 注解基本没有区别。

2.6 定义不同的配置点

@EnvironmentProxySPI 注解主要用于配置环境变量相关的配置点。如果我们想要自定义配置,例如从数据库中获取配置信息,可以实现自己的 ProxySPI 注解。

下面是一个自定义 DBProxySPI 注解的示例,我们需要标记上 @ProxySPI 注解,并指定具体的配置获取逻辑实现类 AnnotationProxyFactory。

复制
@Inherited
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ProxySPI(DbProxyFactory.class) // 指定配置获取逻辑
public @interface DBProxySPI {
    String value();
}

@Component
publicclass DbProxyFactory implements AnnotationProxyFactory<DBProxySPI> {
    @Autowired
    private SysConfigMapper sysConfigDao;

    @Override
    public Object getProxy(Class<?> targetClass, DBProxySPI spi) {
        // 根据注解从数据库获取要注入的实现类
        String configName = sysConfigDao.getConfig(spi.value());
        return springContext.getBean(configName);
    }
}

@DBProxySPI("${sms.impl}")
publicinterface SmsService {
}

通过以上的步骤,我们就可以灵活地实现动态切换服务提供商的功能,并且可以根据不同的需求自定义配置获取逻辑。spring-smart-di 为我们提供了一种简洁、高效的方式来处理这种动态切换的场景,让我们的代码更加灵活和易于维护。

相关资讯

速看!新版SpringAI的两个致命问题

无论是使用最新正式版的 Spring AI,还是最新正式版 Spring AI Alibaba,在实现自定义 MCP 服务器端和客户端的时候,一定要注意这两个问题,不然你会发现你的 MCP 服务器端能启动,但客户端就是连接不上,并且控制台也都是误报信息。 注意事项一自定义 MCP 服务器端添加依赖时,如果是非标准 stdio 模式,当前项目一定要记得排除掉 spring-boot-starter-web 依赖:复制也就是说,你的 spring-ai-starter-mcp-server-webflux 依赖不能和 spring-boot-starter-web 依赖并存,以下是错误配置:复制因为当有 spring-boot-starter-web 依赖时会默认使用 tomcat 启动服务,这样项目虽然启动了,但 mcp service 服务并未启动,mcp service 服务是使用 netty 启动的,如下图所示:图片注意事项二Spring AI 正式版之后,在使用客户端注册 MCP 工具时要使用 ToolCallbacks 而不是 Tools,如果在新版本中使用后者就会启动报错。 错误用法复制或者以下方式也是错误的:复制正确用法复制小结在进行 Spring AI 或 Spring AI Alibaba 老项目升级时,或使用最新正式版框架时,一定要注意这两个问题,不然就会导致自定义的 MCP 服务能启动,但客户端就是连接不上的问题。
6/30/2025 1:55:00 AM
磊哥

Deepseek4j再更新:Java应用一行代码集成DeepSeek

deepseek4j 是什么deepseek4j() 是一个专为 Java 开发者打造的 DeepSeek 模型集成框架。 通过优雅的 API 设计,只需一行代码,即可实现接入 DeepSeek,并获得以下核心能力:完整思维链保留:完美保留 DeepSeek 模型的推理过程,让 AI 的思考过程可追溯流式输出体验:基于 Reactor 实现的流式响应,带来类 ChatGPT 的打字机效果复制使用 deepseek4j,您可以专注于业务逻辑开发,而无需关心底层细节。 一、v1.3 更新内容1.1 联网搜索支持1739118403新版本最重要的更新是引入了联网搜索能力,这一功能带来三个关键优势:突破时间边界:模型不再受限于预训练数据的时间范围,可以获取和处理最新信息实时信息获取:通过高质量信息源获取实时资讯,提供更精准的问答服务差异化竞争:在大模型同质化严重的当下,联网搜索成为关键的差异化竞争点复制1.2 智能系统提示词1739118117系统提示词(System Prompt)是基于模型开发的应用程序内置的指令,让决定了模型在特定上下文中的表现方式、回答风格和功能范围。
2/10/2025 10:49:51 AM
冷冷

Spring 宣布接入 DeepSeek

DeepSeek 是深度求索公司发布的大模型,是国产之光。 大家应该学会如何使用 DeepSeek 大模型,下面我们将看下如何开发基于 DeepSeek 大模型的智能应用。 DeepSeek 大模型DeepSeek 推出两款模型;DeepSeek V 系列,对于V系列主要 对话,模型名称:deepseek-chatDeepSeek R 系统,对于R系统主要 推理, 模型名称:deepseek-reasonerDeepSeek 官方更新日志,可以看到模型发布和演化的过程。
2/17/2025 12:25:00 AM
不才陈某
  • 1