Backend Development 8 min read

Dynamic Service Switching in Spring Boot Using spring‑smart‑di

This article explains how to implement dynamic switching of service implementations in a Spring Boot application by leveraging the spring‑smart‑di library, covering configuration setup, custom annotations, and code examples that enable runtime changes without restarting the service.

macrozheng
macrozheng
macrozheng
Dynamic Service Switching in Spring Boot Using spring‑smart‑di

0. Background

When a system integrates multiple service providers for the same functionality, developers often need a fast way to switch providers based on availability or pricing. The traditional approach stores each provider implementation and selects the active one via a configuration point (e.g., a database or Nacos), retrieving the current provider each time a request is processed.

For example, a system may integrate several SMS providers and allow users to switch between them dynamically.

Step 1: Configure the current provider, e.g.,

sms.impl = "某腾短信"

.

Step 2: In the sending logic, read

sms.impl

, obtain the corresponding implementation class, and invoke its method.

<code>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);
}</code>

Spring's

@Autowired

can be extended so that the injected bean automatically follows the configuration, eliminating the need to manually fetch the provider each time. This is where

spring-smart-di

and its

AutowiredProxySPI

come into play.

1. spring‑smart‑di

spring‑smart‑di extends Spring's

@Autowired

mechanism, allowing developers to define custom injection logic. It currently provides two annotations:

@SmartAutowired

and

@AutowiredProxySPI

. The article focuses on using

@AutowiredProxySPI

for dynamic switching.

2. Quick Start

Add the Maven dependency:

<code>&lt;dependency&gt;
    &lt;groupId&gt;io.github.burukeyou&lt;/groupId&gt;
    &lt;artifactId&gt;spring-smart-di-all&lt;/artifactId&gt;
    &lt;version&gt;0.2.0&lt;/version&gt;
&lt;/dependency&gt;</code>

Enable the feature on a Spring configuration class with

@EnableSmartDI

.

2.1 @EnvironmentProxySPI Annotation

@EnvironmentProxySPI

marks a configuration point that determines how to obtain the concrete implementation class, typically from an environment variable.

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

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

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

2.2 Configuring the Active Provider

Specify the active provider in a configuration file (e.g.,

application.yml

); the value can be a bean alias, component name, or fully qualified class name.

<code>sms:
  impl: 某移短信服务</code>

2.3 Using @AutowiredProxySPI

Inject the service just like a regular

@Autowired

field:

<code>// Dependency injection
@AutowiredProxySPI
private SmsService smsService;</code>

Changing the

${sms.impl}

value updates the injected proxy in real time without restarting the application.

2.4 Defining Custom Configuration Points

While

@EnvironmentProxySPI

reads from environment variables, developers can create custom annotations (e.g.,

@DBProxySPI

) to fetch configuration from a database. The custom annotation is marked with

@ProxySPI

and points to a factory that implements the retrieval logic.

<code>@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 {}
</code>

Project repository: https://github.com/burukeYou/spring-smart-di

Javadynamic configurationSpring Bootdependency injectionspring-smart-di
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.