1. Overview

Spring Cloud Config is part of the Spring Cloud umbrella project. It manages application configuration data through a centralized service so that it’s distinctly separated from your deployed microservices. Spring Cloud Config has its own property management repository but also integrates with open-source projects such as Git, Consul, and Eureka.

In this article, we’ll see different ways of overriding the values of remote properties in Spring Cloud Config, the limitations imposed by Spring from version 2.4, and the changes coming with version 3.0. For this tutorial, we’ll be using spring-boot version 3.2.2.

2. Creating a Spring Config Server

To externalize the configuration files, let’s create our edge service using Spring Cloud Config. It’s positioned as a distribution server for configuration files. We’ll use a filesystem repository in this article.

2.1. Creating the Configuration File

Configurations defined in an application.properties file are shared with all client applications. It is also possible to define specific configurations for an application or a given profile.

Let’s start by creating the configuration file that contains the properties served to our client application. We’ll name our client application ‘baeldung’. Inside a /resources/config folder, let’s create a baeldung.properties file.

2.2. Adding Properties

Let’s add some properties to our baeldung.properties file, which we’ll then use in our client application:

hello=Hello Jane Doe!
welcome=Welcome Jane Doe!

Let’s also add a shared property in a resources/config/application.properties file, which Spring will share across all clients:

shared-property=This property is shared accross all client applications

2.3. The Spring-Boot Config Server Application

Now, let’s create the Spring application that will serve our configuration. We’ll also need the spring-cloud-config-server dependency:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

Once that’s installed, let’s create the application and enable the configuration server:

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServer.class, args);
    }
}

Let’s add the following properties in the application.properties file of our application to tell it to start on port 8081 and to load the previously defined configuration:

server.port=8081
spring.cloud.config.server.native.searchLocations=classpath:/config

Now, let’s start our server application, activating the native profile and allowing us to use the filesystem as a configuration repository:

mvn spring-boot:run -Dspring-boot.run.profiles=native

Our server is now running and serving our configuration. Let’s verify that our shared property is accessible:

$ curl localhost:8081/unknownclient/default
{
  "name": "unknownclient",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": null,
  "state": null,
  "propertySources": [
    {
      "name": "classpath:/config/application.properties",
      "source": {
        "shared-property": "This property is shared accross all client applications"
      }
    }
  ]
}

As well as properties specific to our application:

$ curl localhost:8081/baeldung/default
{
  "name": "baeldung",
  "profiles": [
    "default"
  ],
  "label": null,
  "version": null,
  "state": null,
  "propertySources": [
    {
      "name": "classpath:/config/baeldung.properties",
      "source": {
        "hello": "Hello Jane Doe!",
        "welcome": "Welcome Jane Doe!"
      }
    },
    {
      "name": "classpath:/config/application.properties",
      "source": {
        "shared-property": "This property is shared accross all client applications"
      }
    }
  ]
}

We indicate to the server the name of our application as well as the profile used, default.

We haven’t disabled the spring.cloud.config.server.accept-empty property, which defaults to true. If the application is unknown (unknownclient), the configuration server returns the shared properties anyway.

3. The Client Application

Let’s now create a client application that loads the configuration served by our server on startup.

3.1. Project Setup and Dependencies

Let’s add the spring-cloud-starter-config dependency to load the configuration and spring-boot-starter-web to create controllers in our pom.xml:

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

3.2. Creating the Client Application

Next, let’s create the client application that’ll read the configuration from our spring-cloud-config server:

@SpringBootApplication
public class Client {
    public static void main(String[] args) {
        SpringApplication.run(Client.class, args);
    }
}

3.3. Fetching the Configuration

Let’s modify our application.properties file to tell spring-boot to fetch its configuration from our server:

spring.cloud.config.name=baeldung
spring.config.import=optional:configserver:http://localhost:8081

We also specify that the name of our application is ‘baeldung’ to take advantage of the dedicated properties.

3.4. Adding a Simple Controller

Now let’s create a controller responsible for displaying the specific properties of our configuration, as well as the shared property:

@RestController
public class HelloController {

    @Value("${hello}")
    private String hello;

    @Value("${welcome}")
    private String welcome;

    @Value("${shared-property}")
    private String shared;

    @GetMapping("hello")
    public String hello() {
        return this.hello;
    }

    @GetMapping("welcome")
    public String welcome() {
        return this.welcome;
    }

    @GetMapping("shared")
    public String shared() {
        return this.shared;
    }
}

Now we can navigate to these three URLs to verify that our configuration is taken into account:

$ curl http://localhost:8080/hello
Hello Jane Doe!
$ curl http://localhost:8080/welcome
Welcome Jane Doe!
$ curl http://localhost:8080/shared
This property is shared accross all client applications

4. Overriding the Properties on the Server’s Side

It is possible to override the properties defined for a given application by modifying the server configuration.

Let’s edit our server’s resources/application.properties file to override the hello property:

spring.cloud.config.server.overrides.hello=Hello Jane Doe – application.properties!

Let’s test the call to the /hello controller again to verify that the overload is taken into account:

$ curl http://localhost:8080/hello
Hello Jane Doe - application.properties!

It’s possible to add this overload at the shared configuration level in the resources/config/application.properties file. In this case, it will take priority over the one defined above.

5. Overriding the Properties on the Client’s Side

Since Spring Boot version 2.4, it is no longer possible to override properties via the application.properties file of the client application.

5.1. Using Spring Profiles

We can, however, use Spring profiles. Properties defined locally in profiles have a higher priority than priorities defined for an application at the server level.

Let’s add to our client application an application-development.properties configuration file with the hello property overridden:

hello=Hello local property!

Now, let’s launch our client by activating the development profile:

mvn spring-boot:run -Drun.profiles=development

We can now test our controller /hello again to verify that the overloading is correctly working:

$ curl http://localhost:8080/hello
Hello local property!

5.2. Using Placeholders

We can value properties using placeholders. Thus, the server will provide a default value, which can be overridden by a client-side defined property.

Let’s remove the overload for our hello property from our server’s resources/application.properties file and modify the one in config/baeldung.properties to incorporate the use of a placeholder:

hello=${app.hello:Hello Jane Doe!}

Thus, the server provides a default value that can be overridden if the client declares a property called app.hello.

Let’s edit our client’s resources/application.properties file to add the property:

app.hello=Hello, overriden local property!

Let’s test our controller hello again to verify that the overcharge is correctly taken into account:

$ curl http://localhost:8080/hello
Hello, overriden local property!

Note that if the hello property is also defined in a profile configuration, the latter will take precedence.

6. Legacy Configuration

It’s possible since spring-boot 2.4 to use “legacy configuration”. This allows us to use the old properties management system before the changes made by version 2.4 of spring-boot.

6.1. Loading the External Configuration

Before version 2.4, the management of external configurations is ensured by a bootstrap. We’ll need the spring-cloud-starter-bootstrap dependency. Let’s add this to our pom.xml:

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

Next, we’ll create a bootstrap.properties file in the resources folder and configure the access URL to our server:

spring.cloud.config.name=baeldung
spring.cloud.config.uri=http://localhost:8081

Let’s enable the legacy configuration in application.properties:

spring.config.use-legacy-processing=true

6.2. Enabling the Overriding Capability

On the server side, we need to indicate that property overloading is possible. Let’s modify our baeldung.properties file in this way:

spring.cloud.config.overrideNone=true

Thus, external properties will not have priority over those defined in the application JAR.

6.3. Overriding the Server’s Properties

We can now override the hello property in our client application via the application.properties file:

hello=localproperty

Let’s test the call to our controller:

$ curl http://localhost:8080/hello
localproperty

6.4. The Legacy Configuration Depreciation

Enabling the legacy configuration is no longer possible since Spring Boot version 3.0. In this case, we should use the other methods proposed above.

7. Conclusion

In this article, we’ve seen different ways of overriding the values of remote properties in Spring Cloud Config.

It’s possible to override the properties from the server for those defined for a given application. It’s also possible to override properties at the client level using profiles or placeholders. We’ve also looked at how to activate the legacy configuration to return to the old properties management system.

As always, the source code is available over on GitHub.