Dynamically Load Spring Properties from External Repositories.

Dynamically Load Spring Properties from External Repositories.

ยท

3 min read

Managing configurations dynamically is a crucial requirement in modern applications. In this article, we'll explore how to dynamically load Spring properties from external repositories by extending the EnvironmentPostProcessor and EnumerablePropertySource classes. This approach allows you to integrate external configuration sources seamlessly into your Spring application, ensuring flexibility and scalability.


Why Dynamically Load Properties?

Dynamic property loading is beneficial for several scenarios:

  1. Centralized Configuration: Applications using a central configuration repository (e.g., AWS Parameter Store, Consul, etc.) can dynamically fetch settings during startup or runtime.

  2. Environment-Specific Settings: Load properties specific to a deployment environment without modifying application code.

  3. Enhanced Security: Sensitive properties can be securely fetched from vaults or encrypted repositories.


Key Classes: EnvironmentPostProcessor and EnumerablePropertySource

  1. EnvironmentPostProcessor:

    • Used to customize the Spring Environment before the application context is refreshed.

    • Ideal for adding or modifying property sources programmatically.

  2. EnumerablePropertySource:

    • Represents a property source with enumerable property names.

    • Used to define custom property sources for external repositories.


Step-by-Step Implementation

1. Add Dependencies

Make sure your pom.xml or build.gradle includes the required dependencies to access external repositories (e.g., for HTTP, AWS, or Consul).

Example (pom.xml):

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

2. Implement a Custom EnvironmentPostProcessor

The EnvironmentPostProcessor is invoked early in the application startup lifecycle, enabling you to register custom property sources.

Example:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;

public class CustomPropertyLoader implements EnvironmentPostProcessor {

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        // Register the custom property source
        CustomPropertySource propertySource = new CustomPropertySource("customProperties");
        environment.getPropertySources().addLast(propertySource);
    }
}

3. Implement a Custom EnumerablePropertySource

The EnumerablePropertySource is responsible for fetching properties dynamically from an external repository.

Example:

import org.springframework.core.env.EnumerablePropertySource;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class CustomPropertySource extends EnumerablePropertySource<Map<String, String>> {

    private final Map<String, String> properties = new HashMap<>();

    public CustomPropertySource(String name) {
        super(name);
        loadProperties();
    }

    private void loadProperties() {
        // Fetch properties dynamically from an external source (e.g., REST API, database)
        properties.put("app.dynamic.property1", "value1");
        properties.put("app.dynamic.property2", "value2");
    }

    @Override
    public String[] getPropertyNames() {
        Set<String> keys = properties.keySet();
        return keys.toArray(new String[0]);
    }

    @Override
    public Object getProperty(String name) {
        return properties.get(name);
    }
}

4. Register the Custom EnvironmentPostProcessor

To register the EnvironmentPostProcessor, create a spring.factories file in the META-INF directory.

Example (META-INF/spring.factories):

org.springframework.boot.env.EnvironmentPostProcessor=com.example.CustomPropertyLoader

5. Access Dynamic Properties in Your Application

Once the custom property loader is registered, you can access the dynamically loaded properties like any other Spring property.

Example (application.properties):

app.dynamic.property1=${app.dynamic.property1:defaultValue1}
app.dynamic.property2=${app.dynamic.property2:defaultValue2}

Example (Java Code):

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class PropertyReader {

    @Value("${app.dynamic.property1}")
    private String property1;

    @Value("${app.dynamic.property2}")
    private String property2;

    public void printProperties() {
        System.out.println("Dynamic Property 1: " + property1);
        System.out.println("Dynamic Property 2: " + property2);
    }
}

Extending the Example

Here are some additional ideas to extend the implementation:

  1. Fetch Properties from a REST API: Replace the loadProperties() method in CustomPropertySource to retrieve data from an external REST endpoint.

     private void loadProperties() {
         // Simulate a REST call
         properties.put("api.key", "12345");
         properties.put("api.secret", "secretValue");
     }
    
  2. Use a Vault for Secure Properties: Integrate with services like HashiCorp Vault to dynamically load secure configurations.

  3. Refresh Properties at Runtime: Combine with Spring Boot Actuator to refresh dynamic properties without restarting the application.


Benefits of This Approach

  1. Decoupled Configuration Management: No need to bundle all configurations with the application.

  2. Enhanced Flexibility: Dynamically load configurations based on external conditions or user needs.

  3. Improved Security: Store sensitive properties securely in external systems.


External References

  1. Spring Framework Documentation:
    https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-environment

  2. Spring Boot External Configuration:
    https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config

  3. Using HashiCorp Vault with Spring Boot:
    https://spring.io/guides/gs/vault-config/


By following this approach, you can implement a flexible, secure, and scalable solution for dynamic property management in your Spring Boot application.

More such articles:

medium.com/techwasti

youtube.com/@maheshwarligade

techwasti.com/series/spring-boot-tutorials

techwasti.com/series/go-language

Did you find this article valuable?

Support techwasti by becoming a sponsor. Any amount is appreciated!

ย