Backend Development 9 min read

Dynamic Service Provider Switching with spring-smart-di and AutowiredProxySPI

This article explains how to dynamically switch between multiple service providers in a Spring backend by configuring identifiers, using spring-smart-di's AutowiredProxySPI and related annotations, and provides step‑by‑step code examples for seamless, runtime‑configurable dependency injection.

Architecture Digest
Architecture Digest
Architecture Digest
Dynamic Service Provider Switching with spring-smart-di and AutowiredProxySPI

In real‑world backend development, a single feature often needs to integrate with multiple service providers to avoid downtime and to optimize costs; switching providers quickly is essential for stability and cost control.

The traditional method creates a separate implementation class for each provider and stores the active provider name in a configuration point (e.g., a database or Nacos). Every business call reads this configuration and manually loads the corresponding class.

For example, when integrating several SMS providers, the system can dynamically choose which provider to use based on a configuration value.

Step 1: Define the current provider in a configuration location, such as Nacos or a database. sms.impl = "某腾短信"

Step 2: In the code that sends an SMS, retrieve the provider name and obtain the corresponding implementation class. Example pseudocode:

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

This manual approach is cumbersome because each call must read the configuration and load the class. A more elegant solution is to let Spring’s @Autowired automatically inject the implementation based on the configuration, updating automatically when the configuration changes. The spring-smart-di library provides AutowiredProxySPI to achieve this.

1. spring-smart-di Overview

spring-smart-di extends Spring’s @Autowired with custom injection logic, offering two key annotations: @SmartAutowired and @AutowiredProxySPI . This article focuses on using AutowiredProxySPI for dynamic provider switching.

2. Quick Start

2.1 Add Dependency

Include the library in your Maven pom.xml :

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

2.2 Enable Feature

Annotate a Spring configuration class with @EnableSmartDI to activate the library.

2.3 Use @EnvironmentProxySPI

This annotation marks a configuration point that determines how to obtain the concrete implementation. For the SMS example, annotate the service interface with @EnvironmentProxySPI("${sms.impl}") and store the provider name in a property.

@EnvironmentProxySPI("${sms.impl}")
public interface SmsService {}

@BeanAliasName("某腾短信服务")
@Component
public class ASmsService implements SmsService {}

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

2.4 Configure Current Provider

Set the active provider in your configuration file (YAML, properties, etc.). The value can be the alias defined by @BeanAliasName , a component name, or a fully‑qualified class name.

sms:
  impl: 某移短信服务

2.5 Inject with @AutowiredProxySPI

Inject the service just like a normal @Autowired field:

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

The proxy fetches the current implementation at each call, so changing ${sms.impl} takes effect immediately without restarting the application.

2.6 Define Custom Configuration Points

If you need a non‑environment source (e.g., a database), create a custom annotation such as @DBProxySPI and implement a ProxySPI factory:

@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
{
    @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}")
public interface SmsService {}

With these steps, you can flexibly switch service providers at runtime, and spring-smart-di keeps the code clean, maintainable, and responsive to configuration changes.

JavaBackend DevelopmentSpringdynamic configurationdependency injectionService Provider
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.