SoFunction
Updated on 2025-04-13

Spring-Smart-DI dynamically switched to implement the class

Preface: In actual system development scenarios, we often encounter such a requirement: the same function requires multiple service providers. This is mainly based on two important reasons.
First, in order to avoid the risk of unavailability of a service provider, so that when problems arise, you can quickly switch to other service providers to ensure the stability of the system and the continuity of the business;
Second, there are differences in charging standards for different service providers. From the perspective of cost control, it is necessary to flexibly switch based on actual conditions.

The traditional fast switching logic implementation method is to first write the corresponding implementation class for each service provider, and then configure the service provider currently in use at the configuration point (this configuration point can be a database or a configuration center like Nacos). Each time the relevant business logic is executed, the service provider information currently used must be obtained from the configuration point, and then the service provider corresponding business logic must be executed.

Taking the system access to multiple SMS service providers as an example, users can dynamically switch between different service providers according to their own needs. Let’s take a closer look at what the specific steps will be if this function is implemented manually.

The first step is to configure the identification value corresponding to the currently used service provider in a configuration location (such as Nacos or database). For example, we set = "Key Teng SMS".

The second step is to manually obtain the corresponding service provider implementation class when executing text messages in the code. Here is the corresponding pseudocode example:

void sendSmsTouser(Req req) {
    // 1. Obtain the current service provider    String name = get("");
    // 2. Get the corresponding implementation class    SmsService smsService = (name);
    // 3. Use smsService to execute specific business logic    (req);
}

However, this implementation method has obvious disadvantages. It is quite cumbersome. Each execution requires manual acquisition of configuration and loading the corresponding implementation class. So, is there a more elegant way to allow Spring's @Autowired annotation to automatically inject corresponding implementation classes according to the configuration of the configuration point during injection, and when the configuration changes, the injected implementation classes can also be automatically updated? The @AutowiredProxySPI of spring-smart-di was designed to solve this problem.

1. Introduction to spring-smart-di

--------------------------------------------------------------------------------------

spring-smart-di is an innovative extension to Spring@Autowired annotations, which provides users with the ability to customize Autowired injection logic. Currently, it implements two very important annotations: @SmartAutowired and @AutowiredProxySPI. In this article, we will focus on how to use AutowiredProxySPI to enable the functionality of dynamically switching service providers.

Suppose our system is connected to multiple SMS service providers. Let’s learn more about how to use AutowiredProxySPI to achieve dynamic switching through a quick start case.

2. Start quickly

2.1 Introducing dependencies

First, we need to introduce spring-smart-di dependencies into our project. Add the following dependency code to the file in the Maven project:

<dependency>
    <groupId></groupId>
    <artifactId>spring-smart-di-all</artifactId>
    <version>0.2.0</version>
</dependency>

2.2 Enable function

Mark the @EnableSmartDI annotation on the Spring configuration class to enable the power of spring-smart-di.

2.3 Use of @EnvironmentProxySPI annotations

@EnvironmentProxySPl annotation represents a configuration point, and its main function is to configure how to obtain the logic of the specific implementation class.

Suppose there are two SMS service providers in our system and need to implement dynamic switching. We need to configure the @EnvironmentProxySPl annotation on the interface, indicating that we obtain the current service provider from the environment variable configuration point. Here we store the configuration information in the property ${}.

@EnvironmentProxySPI("${}")
publicinterface SmsService {
}
// Define alias for implementation classes@BeanAliasName("Search SMS Service")
@Component
publicclass ASmsService implements SmsService {
}
@BeanAliasName("Some mobile text message service")
@Component
publicclass BSmsService implements SmsService {
}

2.4 Configure the current service provider

We can configure the service provider currently in the configuration file. The configured value can be the value specified by the @BeanAliasName annotation, the value specified by the @Component annotation, or the specific full path class name.

sms:
  impl: A certain SMS service

2.5 @AutowiredProxySPI Injection

Next, we just need to use the @AutowiredProxySPI annotation just like using the @Autowired annotation.

// Dependency injection@AutowiredProxySPI
private SmsService smsService;

Through the above steps, we have successfully completed the requirements of dynamic switching service providers. As long as we change the value of the configuration property ${}, the system will take effect in real time without restarting the service. This is because @AutowiredProxySPI injects a proxy object. Each time it executes, it will first get the currently used implementation class in real time, and then perform the call operation. Moreover, there is basically no difference in using the @Autowired annotation directly.

2.6 Define different configuration points

@EnvironmentProxySPI annotation is mainly used to configure configuration points related to environment variables. If we want to customize the configuration, such as getting configuration information from the database, we can implement our own ProxySPI annotations. Below is an example of a custom DBProxySPI annotation. We need to mark the @ProxySPI annotation and specify the specific configuration to get the logical implementation class AnnotationProxyFactory.

@Inherited
@Target({, , })
@Retention()
@ProxySPI() // Specify configuration acquisition logicpublic @interface DBProxySPI {
    String value();
}
@Component
publicclass DbProxyFactory implements AnnotationProxyFactory&lt;DBProxySPI&gt; {
    @Autowired
    private SysConfigMapper sysConfigDao;
    @Override
    public Object getProxy(Class&lt;?&gt; targetClass, DBProxySPI spi) {
        // Obtain the implementation class to be injected from the database according to the annotation        String configName = (());
        return (configName);
    }
}
@DBProxySPI("${}")
publicinterface SmsService {
}

Through the above steps, we can flexibly implement the function of dynamic switching service providers, and can customize the configuration and obtain logic according to different needs. spring-smart-di provides us with a simple and efficient way to handle this dynamic switching scenario, making our code more flexible and easy to maintain.

This is the end of this article about Spring-Smart-DI dynamic switching implementation class. For more related Spring-Smart-DI dynamic switching content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!