Dave
Dave

Reputation: 450

Externalizing configuration in Spring Boot with multiple applications running in the same container

I'm building multiple Spring Boot applications which will be deployed on the same servlet container. But I'm having difficulties getting Spring Boot to work with externalized configuration files the way I want, and not like the framework wants.

Situation:

Problem:

As the applications are deployed on the same JVM, the property spring.config.location has the same value for all applications. I want our applications to all use the same configuration file naming (application.properties), so specifying spring.config.name is not an option.

What I would like:

Questions:

Is there some mechanism to influence or override loading or resolving of external configuration files?

Are there other approaches to get the desired result?

Upvotes: 3

Views: 2783

Answers (2)

Dave
Dave

Reputation: 450

The suggestions of @Iulian Rosca to use a pattern like ${properties_home}/${application_id}/application.properties brought me to the idea of defining a custom JVM property like app.config.root and using this property to override spring.config.location very early in the application lifecycle.

My application class looks now like this and works for embedded and container deployments:

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return configureApplication(builder);
    }

    public static void main(String[] args) {
        configureApplication(new SpringApplicationBuilder()).run(args);
    }

    private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
        return builder
            .sources(Application.class)
            .properties("spring.config.location:${${app.config.root}/myapp1/:#{null}}");
    }

}

Important notes to this solution:

  • app.config.root has to be set externally by JVM or JNDI property
  • app.config.root can only contain a single external configuration path (for my requirements this was sufficient) in contrast to spring.config.location where multiple comma-separated paths can be specified
  • SpringApplicationBuilder.properties(...) sets the application's default properties. Because of this, spring.config.location cannot be specified externally anymore, as JVM or JNDI Properties have priority over default properties and would therefore override spring.config.location again.

Upvotes: 0

Iulian Rosca
Iulian Rosca

Reputation: 1015

You can achieve what you're trying by using @PropertySource. According to the official documentation (Externalized Configuration) you can use this annotation to externalize configuration files, e.g.:

 @Configuration
 @PropertySource("file:/path/to/application.properties")
 public class AppConfig {

 }

As stated in here, inside @PropertySource you can use placeholders that would be resolved against other property sources, for e.g. values declared in application.properties

Assuming that "my.placeholder" is present in one of the property sources already registered, e.g. system properties or environment variables, the placeholder will be resolved to the corresponding value. If not, then "default/path" will be used as a default. Expressing a default value (delimited by colon ":") is optional. If no default is specified and a property cannot be resolved, an IllegalArgumentException will be thrown.

You can declare properties_home as an environment variable and application_id inside your application.properties file.

 @Configuration
 @PropertySource("${properties_home}/${application_id}/application.properties")
 public class AppConfig {

 }

Don't forget to enable support for resolving the placeholders:

In order to resolve ${...} placeholders in bean definitions or @Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using in XML, but must be explicitly registered using a static @Bean method when using @Configuration classes.

Update:

In order to override the properties from the external file you could use a spring profile. Inside the packaged application.properties you need to set:

spring.profiles.active=external

Declare all the properties that you want to take precedence as part of the external profile inside the file located in "${properties_home}/${application_id}/application.properties".

Upvotes: 3

Related Questions