SoFunction
Updated on 2025-05-11

Ten ways to dynamically modify configurations in SpringBoot

introduction

In SpringBoot applications, configuration information is usually done throughorThe file is statically defined, and these configurations are fixed after the application is started.

However, we often need to dynamically modify the configuration without restarting the application to achieve grayscale release, A/B testing, dynamic adjustment of thread pool parameters, switching function switches and other scenarios.

This article will introduce 10 methods to implement dynamic configuration modification in SpringBoot.

1. @RefreshScope combined with Actuator to refresh the endpoint

Offered by Spring Cloud@RefreshScopeAnnotations are the basic method to implement configuration hot refresh.

Implementation steps

  • Add dependencies:
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>
  • Turn on the refresh endpoint:
=refresh
  • Add to the configuration class@RefreshScopeannotation:
@RefreshScope
@RestController
public class ConfigController {
    
    @Value("${:Default message}")
    private String message;
    
    @GetMapping("/message")
    public String getMessage() {
        return message;
    }
}
  • After modifying the configuration, call the refresh endpoint:
curl -X POST http://localhost:8080/actuator/refresh

Pros and cons

advantage

  • Simple implementation, leveraging the off-the-shelf features provided by Spring Cloud
  • No additional configuration center required

shortcoming

  • Need to trigger refresh manually
  • Only single instances can be refreshed, and they need to be called one by one in the cluster environment.
  • Only the values ​​in the configuration source can be reloaded, and new configuration cannot be added dynamically

2. Spring Cloud Config Configuration Center

Spring Cloud Config provides a centralized configuration server that supports version control and dynamic refresh of configuration files.

Implementation steps

  • Setting up Config Server:
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        (, args);
    }
}
=/your-repo/config
  • Client configuration:
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
# 
=my-service
=http://localhost:8888
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

Pros and cons

advantage

  • Provides configuration version control
  • Supports configuration of environment isolation
  • Automatic refresh of cluster configurations can be achieved through Spring Cloud Bus

shortcoming

  • Introduced additional infrastructure complexity
  • Rely on additional message bus to achieve cluster refresh
  • There is a certain delay in configuration update

3. Database-based configuration storage

Store configuration information in the database and enable configuration refresh through timed tasks or event triggering mechanisms.

Implementation plan

  • Create a configuration table:
CREATE TABLE app_config (
    config_key VARCHAR(100) PRIMARY KEY,
    config_value VARCHAR(500) NOT NULL,
    description VARCHAR(200),
    update_time TIMESTAMP
);
  • Implement configuration loading and refreshing:
@Service
public class DatabaseConfigService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    private Map&lt;String, String&gt; configCache = new ConcurrentHashMap&lt;&gt;();
    
    @PostConstruct
    public void init() {
        loadAllConfig();
    }
    
    @Scheduled(fixedDelay = 60000)  // Refresh every minute    public void loadAllConfig() {
        List&lt;Map&lt;String, Object&gt;&gt; rows = ("SELECT config_key, config_value FROM app_config");
        for (Map&lt;String, Object&gt; row : rows) {
            ((String) ("config_key"), (String) ("config_value"));
        }
    }
    
    public String getConfig(String key, String defaultValue) {
        return (key, defaultValue);
    }
}

Pros and cons

advantage

  • Simple and straightforward, no additional components required
  • Configuration visual management can be implemented through the management interface
  • Configure persistence, restart without loss

shortcoming

  • Refresh delay depends on timing task interval
  • Database becomes potential single point of failure
  • Version control and permission management that needs to be configured by yourself

4. Use ZooKeeper to manage configuration

Use ZooKeeper's data change notification mechanism to achieve real-time dynamic update of configuration.

Implementation steps

  • Add dependencies:
<dependency>
    <groupId></groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>
  • Implement configuration listening:
@Component
public class ZookeeperConfigManager {
    
    private final CuratorFramework client;
    private final Map&lt;String, String&gt; configCache = new ConcurrentHashMap&lt;&gt;();
    
    @Autowired
    public ZookeeperConfigManager(CuratorFramework client) {
         = client;
        initConfig();
    }
    
    private void initConfig() {
        try {
            String configPath = "/config";
            if (().forPath(configPath) == null) {
                ().creatingParentsIfNeeded().forPath(configPath);
            }
            
            List&lt;String&gt; keys = ().forPath(configPath);
            for (String key : keys) {
                String fullPath = configPath + "/" + key;
                byte[] data = ().forPath(fullPath);
                (key, new String(data));
                
                // Add a listener                NodeCache nodeCache = new NodeCache(client, fullPath);
                ().addListener(() -&gt; {
                    byte[] newData = ().getData();
                    (key, new String(newData));
                    ("Config updated: " + key + " = " + new String(newData));
                });
                ();
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize config from ZooKeeper", e);
        }
    }
    
    public String getConfig(String key, String defaultValue) {
        return (key, defaultValue);
    }
}

Pros and cons

advantage

  • Real-time notification, effective immediately after configuration changes
  • ZooKeeper provides high availability guarantee
  • Suitable for configuration synchronization in distributed environments

shortcoming

  • ZooKeeper cluster needs to be maintained
  • Configuration management is not as intuitive as dedicated configuration center
  • Performance may be affected when storing large amounts of configurations

5. Redis publish and subscription mechanism implements configuration updates

Use Redis's publish and subscription function to achieve real-time notification of configuration changes.

Implementation plan

  • Add dependencies:
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • Implement configuration refresh monitoring:
@Component
public class RedisConfigManager {
    
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    private final Map&lt;String, String&gt; configCache = new ConcurrentHashMap&lt;&gt;();
    
    @PostConstruct
    public void init() {
        loadAllConfig();
        subscribeConfigChanges();
    }
    
    private void loadAllConfig() {
        Set&lt;String&gt; keys = ("config:*");
        if (keys != null) {
            for (String key : keys) {
                String value = ().get(key);
                (("config:", ""), value);
            }
        }
    }
    
    private void subscribeConfigChanges() {
        ().getConnection().subscribe(
            (message, pattern) -&gt; {
                String[] parts = new String(()).split("=");
                if ( == 2) {
                    (parts[0], parts[1]);
                }
            },
            "config-channel".getBytes()
        );
    }
    
    public String getConfig(String key, String defaultValue) {
        return (key, defaultValue);
    }
    
    // Method for updating configuration (used by the management side)    public void updateConfig(String key, String value) {
        ().set("config:" + key, value);
        ("config-channel", key + "=" + value);
    }
}

Pros and cons

advantage

  • Simple implementation, leveraging Redis's publish and subscription mechanism
  • Real-time and efficient configuration synchronization in cluster environment
  • Can be integrated with existing Redis infrastructure

shortcoming

  • Relying on Redis availability
  • Need to ensure that messages are not lost
  • Lack of version control and auditing capabilities

6. Customize the configuration loader and listener

Customize SpringPropertySourceand file monitoring mechanism to realize dynamic loading of local configuration files.

Implementation plan

@Component
public class DynamicPropertySource implements ApplicationContextAware {
    
    private static final Logger logger = ();
    private ConfigurableApplicationContext applicationContext;
    private File configFile;
    private Properties properties = new Properties();
    private FileWatcher fileWatcher;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         = (ConfigurableApplicationContext) applicationContext;
        try {
            configFile = new File("config/");
            if (()) {
                loadProperties();
                registerPropertySource();
                startFileWatcher();
            }
        } catch (Exception e) {
            ("Failed to initialize dynamic property source", e);
        }
    }
    
    private void loadProperties() throws IOException {
        try (FileInputStream fis = new FileInputStream(configFile)) {
            (fis);
        }
    }
    
    private void registerPropertySource() {
        MutablePropertySources propertySources = ().getPropertySources();
        PropertiesPropertySource propertySource = new PropertiesPropertySource("dynamic", properties);
        (propertySource);
    }
    
    private void startFileWatcher() {
        fileWatcher = new FileWatcher(configFile);
        (new FileChangeListener() {
            @Override
            public void fileChanged() {
                try {
                    Properties newProps = new Properties();
                    try (FileInputStream fis = new FileInputStream(configFile)) {
                        (fis);
                    }
                    
                    // Update existing properties                    MutablePropertySources propertySources = ().getPropertySources();
                    PropertiesPropertySource oldSource = (PropertiesPropertySource) ("dynamic");
                    if (oldSource != null) {
                        ("dynamic", new PropertiesPropertySource("dynamic", newProps));
                    }
                    
                    // Publish configuration change events                    (new EnvironmentChangeEvent(("dynamic")));
                    
                    ("Dynamic properties reloaded");
                } catch (Exception e) {
                    ("Failed to reload properties", e);
                }
            }
        });
        ();
    }
    
    // File listener implementation (simplified version)    private static class FileWatcher extends Thread {
        private final File file;
        private FileChangeListener listener;
        private long lastModified;
        
        public FileWatcher(File file) {
             = file;
             = ();
        }
        
        public void setListener(FileChangeListener listener) {
             = listener;
        }
        
        @Override
        public void run() {
            try {
                while (!()) {
                    long newLastModified = ();
                    if (newLastModified != lastModified) {
                        lastModified = newLastModified;
                        if (listener != null) {
                            ();
                        }
                    }
                    (5000);  // Check intervals                }
            } catch (InterruptedException e) {
                // Thread interrupt            }
        }
    }
    
    private interface FileChangeListener {
        void fileChanged();
    }
}

Pros and cons

advantage

  • No dependence on external services, complete autonomous control
  • Can monitor local file changes to achieve real-time refresh
  • Suitable for single applications or simple scenarios

shortcoming

  • Configuration distribution requires additional mechanism support
  • Configuration consistency is difficult to ensure in cluster environment
  • Need more custom code

7. Apollo Configuration Center

Ctrip's open source Apollo is a powerful distributed configuration center that provides complete functions such as configuration modification, release, and rollback.

Implementation steps

  • Add dependencies:
<dependency>
    <groupId></groupId>
    <artifactId>apollo-client</artifactId>
    <version>2.0.1</version>
</dependency>
  • Configure the Apollo client:
# 
=your-app-id
=http://apollo-config-service:8080
  • Enable Apollo:
@SpringBootApplication
@EnableApolloConfig
public class Application {
    public static void main(String[] args) {
        (, args);
    }
}
  • Use configuration:
@Component
public class SampleService {
    
    @Value("${timeout:1000}")
    private int timeout;
    
    // Listen to specific configuration changes    @ApolloConfigChangeListener
    public void onConfigChange(ConfigChangeEvent event) {
        if (("timeout")) {
            ConfigChange change = ("timeout");
            ("timeout changed from " + () + " to " + ());
            // Specific logic can be executed here, such as reinitializing thread pools, etc.        }
    }
}

Pros and cons

advantage

  • Provide a complete configuration management interface
  • Supports configuration grayscale release
  • Have permission control and operational audit
  • Automatic cluster synchronization without manual refresh

shortcoming

  • Apollo infrastructure needs to be deployed and maintained
  • The learning cost is relatively high
  • Small projects may be too heavy

8. Nacos Configuration Management

Alibaba's open source Nacos is not only a service discovery component, but also a configuration center, and is widely used in the Spring Cloud Alibaba ecosystem.

Implementation steps

  • Add dependencies:
<dependency>
    <groupId></groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  • Configure Nacos:
# 
=my-service
-addr=127.0.0.1:8848
# Support multiple configuration files-configs[0].data-id=
-configs[0].group=DEFAULT_GROUP
-configs[0].refresh=true
  • Use configuration:
@RestController
@RefreshScope
public class ConfigController {
    
    @Value("${useLocalCache:false}")
    private boolean useLocalCache;
    
    @GetMapping("/cache")
    public boolean getUseLocalCache() {
        return useLocalCache;
    }
}

Pros and cons

advantage

  • Seamless integration with Spring Cloud Alibaba ecosystem
  • Configuration and service discovery functions two-in-one
  • Lightweight, easy to deploy and use
  • Supports dynamic refresh and listening for configuration

shortcoming

  • Some advanced features are not as rich as Apollo
  • Need to maintain additional Nacos servers
  • Need to use bootstrap configuration mechanism

9. Spring Boot Admin combined with Actuator

Spring Boot Admin provides a Web UI to manage and monitor Spring Boot applications, and combines Actuator's environment endpoints to realize visual management of configuration.

Implementation steps

  • Set up Spring Boot Admin server:
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.7.0</version>
</dependency>
@SpringBootApplication
@EnableAdminServer
public class AdminServerApplication {
    public static void main(String[] args) {
        (, args);
    }
}
  • Configure client applications:
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
=http://localhost:8080
=*
=true
  • Modify configuration through Spring Boot Admin UI

Spring Boot Admin provides a UI interface that allows you to view and modify the application's environment properties. By sending a POST request to/actuator/envEndpoint modification configuration.

Pros and cons

advantage

  • Provides a visual operation interface
  • Integrate with Spring Boot's own monitoring capabilities
  • No additional configuration center components required

shortcoming

  • The modified configuration is not persistent and is lost after the application restarts.
  • Weak security and additional protection is required
  • Configuration management that is not suitable for large-scale production environments

10. Use @ConfigurationProperties in conjunction with EventListener

Leverage Spring's event mechanism and@ConfigurationPropertiesBinding function to realize dynamic update of configuration.

Implementation plan

  • Define configuration property class:
@Component
@ConfigurationProperties(prefix = "app")
@Setter
@Getter
public class ApplicationProperties {
    
    private int connectionTimeout;
    private int readTimeout;
    private int maxConnections;
    private Map&lt;String, String&gt; features = new HashMap&lt;&gt;();
    
    // Method to initialize the client    public HttpClient buildHttpClient() {
        return ()
                .connectTimeout((connectionTimeout))
                .build();
    }
}
  • Add configuration refresh mechanism:
@Component
@RequiredArgsConstructor
public class ConfigRefresher {
    
    private final ApplicationProperties properties;
    private final ApplicationContext applicationContext;
    private HttpClient httpClient;
    
    @PostConstruct
    public void init() {
        refreshHttpClient();
    }
    
    @EventListener()
    public void onEnvironmentChange() {
        refreshHttpClient();
    }
    
    private void refreshHttpClient() {
        httpClient = ();
        ("HttpClient refreshed with timeout: " + ());
    }
    
    public HttpClient getHttpClient() {
        return ;
    }
    
    // How to manually trigger configuration refresh    public void refreshProperties(Map&lt;String, Object&gt; newProps) {
        PropertiesPropertySource propertySource = new PropertiesPropertySource(
                "dynamic", convertToProperties(newProps));
        
        ConfigurableEnvironment env = (ConfigurableEnvironment) ();
        ().addFirst(propertySource);
        
        // Trigger environment change event        (new EnvironmentChangeEvent(()));
    }
    
    private Properties convertToProperties(Map&lt;String, Object&gt; map) {
        Properties properties = new Properties();
        for (&lt;String, Object&gt; entry : ()) {
            ((), ().toString());
        }
        return properties;
    }
}

Pros and cons

advantage

  • Strongly typed configuration binding
  • Leverage Spring built-in mechanisms without additional components
  • High flexibility, can be combined with other configuration sources

shortcoming

  • Need to write more code
  • Configuration change notifications need additional implementation
  • Not suitable for large-scale or cross-service configuration management

Method comparison and selection guide

method Ease of use Functional integrity Applicable scale Real-time
@RefreshScope+Actuator ★★★★★ ★★ Small Manual trigger
Spring Cloud Config ★★★ ★★★★ Medium and large Need to configure
Database storage ★★★★ ★★★ Medium size Timely refresh
ZooKeeper ★★★ ★★★ Medium size real time
Redis Publish Subscription ★★★★ ★★★ Medium size real time
Custom configuration loader ★★ ★★★ Small Timely refresh
Apollo ★★★ ★★★★★ Medium and large real time
Nacos ★★★★ ★★★★ Medium and large real time
Spring Boot Admin ★★★★ ★★ Small Manual trigger
@ConfigurationProperties+ Event ★★★ ★★★ Small Event trigger

Summarize

Dynamic configuration modification can improve the flexibility and manageability of the system. Choosing a suitable dynamic configuration solution should comprehensively consider the application scale, team familiarity, infrastructure status and business needs.

Regardless of the option you choose, ensuring the security, consistency and traceability of your configuration is critical.

The above is the detailed content of ten methods of SpringBoot dynamically modifying configuration. For more information about SpringBoot dynamically modifying configuration, please follow my other related articles!