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

隐身守侯 提交于 2019-12-10 10:58:14

问题


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:

  • multiple Spring Boot applications will be deployed on a single servlet container (WAR file)
  • the location of configuration files will be set via JVM property spring.config.location
  • embedded deployment is not an option

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:

  • no need to set spring.config.name as the configuration name should be standardized accross all our applications (constant)
  • the externalized configuration properties should override values from application.properties packaged inside my deployed WAR
  • profile specific configurations (application-{profile}) should be possible
  • no hardcoded config locations in code
  • organizing configuration files in a per-application directory layout:

    ${spring.config.location}/app1/application.properties ${spring.config.location}/app2/application.properties ${spring.config.location}/app3/application.properties

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?


回答1:


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".




回答2:


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.


来源:https://stackoverflow.com/questions/44144118/externalizing-configuration-in-spring-boot-with-multiple-applications-running-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!