Dynamic Service Provider Switching with spring-smart-di and AutowiredProxySPI
This article explains how to implement runtime switching of multiple service providers, such as SMS vendors, in a Spring-based backend using the spring‑smart‑di library, @EnvironmentProxySPI, and @AutowiredProxySPI annotations, with configuration stored in Nacos, databases, or environment variables.
In many systems a single function may need to integrate with multiple service providers, and it is necessary to switch quickly when a provider becomes unavailable or its pricing changes. The traditional approach stores each provider implementation and selects the active one via a configuration point (e.g., a database or Nacos entry) at runtime.
For example, a system may integrate several SMS providers and allow users to switch between them dynamically. The article shows how to implement this manually and then introduces a smarter solution using Spring's dependency injection.
Step 1: Configure the current provider, e.g., sms.impl = "某腾短信" , in a configuration source.
Step 2: In the code that sends an SMS, retrieve the configured value sms.impl , obtain the corresponding implementation bean from the Spring context, and invoke its business logic.
void sendSmsTouser(Req req) {
// 1. Get the current provider name
String name = get("sms.impl");
// 2. Retrieve the implementation bean
SmsService smsService = springContext.getBean(name);
// 3. Execute the business logic
smsService.sendMsg(req);
}Using Spring's @Autowired annotation together with the spring‑smart‑di extension, the injection can automatically follow the configuration without explicit lookup code. The key component is AutowiredProxySPI provided by spring‑smart‑di.
1. spring‑smart‑di
spring‑smart‑di extends Spring's @Autowired to allow custom injection logic via two annotations: @SmartAutowired and @AutowiredProxySPI. The article focuses on @AutowiredProxySPI for dynamic switching.
2. Quick Start
First, add the Maven dependency:
<dependency>
<groupId>io.github.burukeyou</groupId>
<artifactId>spring-smart-di-all</artifactId>
<version>0.2.0</version>
</dependency>Enable the feature on a Spring configuration class with @EnableSmartDI.
2.1 @EnvironmentProxySPI Annotation
@EnvironmentProxySPImarks a configuration point that determines how to obtain the concrete implementation class, typically from an environment variable such as ${sms.impl}.
@EnvironmentProxySPI("${sms.impl}")
public interface SmsService {}
@BeanAliasName("某腾短信服务")
@Component
public class ASmsService implements SmsService {}
@BeanAliasName("某移短信服务")
@Component
public class BSmsService implements SmsService {}2.2 Configuring the Current Provider
Set the active provider in a configuration file, e.g.:
sms:
impl: 某移短信服务2.3 Using @AutowiredProxySPI
Inject the service exactly like a normal @Autowired field, but with @AutowiredProxySPI so that the proxy resolves the current implementation at each call.
// Dependency injection
@AutowiredProxySPI
private SmsService smsService;Changing the ${sms.impl} value updates the injected implementation in real time without restarting the service.
2.4 Defining Custom Configuration Points
Custom points such as @DBProxySPI can be created to fetch configuration from a database. The annotation is linked to a factory (e.g., DbProxyFactory) that implements AnnotationProxyFactory to resolve the target bean.
@Inherited
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ProxySPI(DbProxyFactory.class) // specify config retrieval logic
public @interface DBProxySPI {
String value();
}
@Component
public class DbProxyFactory implements AnnotationProxyFactory<DBProxySPI> {
@Autowired
private SysConfigMapper sysConfigDao;
@Override
public Object getProxy(Class<?> targetClass, DBProxySPI spi) {
// Retrieve implementation name from DB based on annotation value
String configName = sysConfigDao.getConfig(spi.value());
return springContext.getBean(configName);
}
}
@DBProxySPI("${sms.impl}")
public interface SmsService {}Other Information
GitHub project: https://github.com/burukeYou/spring-smart-di
Maven Central: https://central.sonatype.com/artifact/io.github.burukeyou/spring-smart-di-all
The library is still evolving; the first version focuses on dynamic switching. Users are encouraged to star the project and provide feedback.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
