How to dynamically refresh the configuration of SpringBoot (scheme)

For microservices, configuration localization is a big problem. It is impossible to restart the service every time you need to change the configuration. Therefore, the final solution is to externalize the configuration and host it on a platform to achieve unnecessary Restart the service to modify multiple valid purposes at once.
But for the Spring Boot project of a single application, dynamic refresh is obviously a bit redundant. Anyway, it’s just a service, just change it and restart it. However, dynamic refresh must be used in some special scenarios.

What are the mainstream solutions under microservices?

There are three mainstream methods for the dynamic configuration center under microservices, as shown in the figure below:

The three configuration center schemes in the above figure can be said to be the most used in enterprises, and they are:

  1. Nacos: Alibaba’s recent open source project, this guy is awesome, one kills Eureka (stopped) and Config + Bus, it can be used as a configuration center as well As a registration center, and has its own independent management platform, it can be said that it is the most mainstream one.

  2. Config + Bus: The microservice configuration center used in the early days can rely on GitHub to manage the configuration files of microservices. This is also used by many enterprises now, but they need to independently deploy a microservice. Compared with Nacos, it is much inferior.

  3. Apollo: Ctrip’s open source project Apollo, which is also used by many companies. Chen doesn’t know much about it. If you are interested, you can study it in depth.

How many solutions are applicable to Spring Boot?

In fact, the above three types can be adapted in the Spring Boot project, but it is a bit heavy as a single application.

1. If the project is a cluster of microservices, the business functions are complex

Suggestion: Spring Boot + Nacos

2. If the project is a single service, the business function is single

Suggestion: Spring Boot + Config + actuator

Spring Boot + manual refresh

For Spring Boot + Nacos

What Ali wants to do is actually a micro-service ecosystem. Nacos can not only be used as the configuration and registration center of Spring Cloud, but also adapted to Dubbo and K8s. The official document has given a detailed introduction on how to adapt, and the author will not discuss it here. Introduced in detail, as shown below:

Of course, Nacos is also applicable to Spring and Spring Boot projects.

How to use it? Here the author only provides the following ideas, without doing too much research. This article will be introduced in detail in the author’s next column Spring Cloud Advanced:

  1. Download the corresponding version of Nacos, start the project, visit http://localhost:8848 to enter the management interface of Nacos;

  2. The configuration of the Spring Boot project that introduces Nacos relies on nacos-config-spring-boot-starter to configure the address of the Nacos management center.

  3. The two annotations @NacosPropertySource and @NacosValue are combined.

  • @NacosPropertySource: Specify the dataId of the configuration center, and whether to refresh automatically

  • @NacosValue replaces the @Value annotation to complete the automatic assembly of attributes

  1. If the company project has been managed in the background, you can directly call the Nacos open API to modify the corresponding configuration value (replacing the manual operation of the Nacos management interface), the address of the API: https://nacos.io/zh-cn/docs/ open-api.html

For Spring Boot + Config + actuator

1. Add Config dependencies, as follows

<!--springCloud dependency-->
<dependencyManagement>
    <dependencies>
        <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    </dependencies>
</dependencyManagement>

<!-- config dependencies -->
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>

  <!-- actuator dependency -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

2. Expose the endpoint of Spring Boot in the configuration file, as follows:

management.endpoints.web.exposure.include=*

3. Add three attribute configurations in the configuration file

config.version=22
config.app.name=dynamic-project
config.platform=mysql

4. Combining the @RefreshScope annotation to dynamically refresh, write a Controller, as follows:

@RestController
//@RefreshScope This annotation must be marked, otherwise the dynamic update cannot be completed
@RefreshScope
public class DynamicConfigController {
    @Value("${config.version}")
    private String version;

    @Value("${config.app.name}")
    private String appName;

    @Value("${config. platform}")
    private String platform;


    @GetMapping("/show/version")
    public String test(){
        return "version=" + version + "-appName=" + appName + "-platform=" + platform;
    }

5. Start the project test

1. Browser access http://localhost:8080/show/version
2. Modify the configuration file in the target directory, as follows:
    config.version=33
    config.app.name=dynamic-project
    config.platform=ORACLE
3. POST request http://localhost:8080/actuator/refresh interface, manually refresh the configuration (required, otherwise it cannot be refreshed automatically)
4. Enter http://localhost:8080/show/version again in the browser

As you can see, the configuration has been automatically modified

For Spring Boot + manual refresh

After source code analysis, the configuration refresh is to publish refresh events, and the refresh is implemented in the listener

Publish event:
    Take nacos as an example: com.alibaba.cloud.nacos.refresh.NacosContextRefresher
    applicationContext.publishEvent(new RefreshEvent(this,null,"Refresh Nacos config"));



Listen for refresh events: org.springframework.cloud.endpoint.event.RefreshEventListener

@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationReadyEvent) {
handle((ApplicationReadyEvent) event);
}
else if (event instanceof RefreshEvent) {
handle((RefreshEvent) event);
}
}

public void handle(ApplicationReadyEvent event) {
this.ready.compareAndSet(false, true);
}


Perform refresh: org.springframework.cloud.context.refresh.ContextRefresher

public synchronized Set<String> refresh() {
Set<String> keys = refreshEnvironment();
this.scope.refreshAll();
return keys;
}

public synchronized Set<String> refreshEnvironment() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}

You can implement dynamic loading based on refreshing yourself

@GetMapping("/show/refresh")
    public String refresh(){
        //Modify the properties in the configuration file
        HashMap<String, Object> map = new HashMap<>();
        map.put("config.version",99);
        map.put("config.app.name","appName");
        map.put("config.platform","ORACLE");
        MapPropertySource propertySource=new MapPropertySource("dynamic", map);
        //Set the modified configuration to the environment
        environment.getPropertySources().addFirst(propertySource);
        //Call the refresh method asynchronously to avoid blocking and waiting for no response
        new Thread(() -> contextRefresher. refresh()). start();
        return "success";
    }

test steps

1. Browser access http://localhost:8080/show/version
2. Modify the configuration file in the target directory, as follows:
    config.version=33
    config.app.name=dynamic-project
    config.platform=ORACLE
3. POST request http://localhost:8080/actuator/refresh interface, manually refresh the configuration (required, otherwise it cannot be refreshed automatically)
4. Enter http://localhost:8080/show/version again in the browser

As you can see, the configuration has been automatically modified

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge Cloud native entry skill treeHomepageOverview 12954 people are studying systematically