在 Spring 中外部化配置 在同一个容器中使用多个应用程序 运行 启动

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

我正在构建多个 Spring 引导应用程序,这些应用程序将部署在同一个 servlet 容器上。但是我很难 Spring 引导以我想要的方式使用外部配置文件,而不是像框架想要的那样。

情况:

问题:

由于应用程序部署在同一个 JVM 上,因此 属性 spring.config.location 对所有应用程序具有相同的值。我希望我们的应用程序都使用相同的配置文件命名 (application.properties),因此指定 spring.config.name 不是一个选项。

我想要什么:

问题:

是否有某种机制可以影响或覆盖外部配置文件的加载或解析?

还有其他方法可以达到预期的效果吗?

您可以使用 @PropertySource 实现您想要的效果。根据官方文档(Externalized Configuration),您可以使用此注释来外部化配置文件,例如:

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

 }

here 中所述,在 @PropertySource 中,您可以使用占位符,这些占位符将针对其他 属性 来源进行解析,例如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.

您可以将 properties_home 声明为环境变量,并在 application.properties 文件中声明 application_id

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

 }

不要忘记启用解析占位符的支持:

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.

更新:

为了覆盖外部文件的属性,您可以使用 spring 配置文件。在打包好的application.properties里面你需要设置:

spring.profiles.active=external

在位于 "${properties_home}/${application_id}/application.properties".

的文件中声明所有您希望优先作为外部配置文件一部分的属性

@Iulian Rosca 关于使用像 ${properties_home}/${application_id}/application.properties 这样的模式的建议让我想到定义一个像 app.config.root 这样的自定义 JVM 属性 并使用这个 属性在应用程序生命周期的早期覆盖 spring.config.location

我的应用程序 class 现在看起来像这样并且适用于嵌入式和容器部署:

@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}}");
    }

}

此解决方案的重要说明:

  • app.config.root 必须由 JVM 或 JNDI 在外部设置 属性
  • app.config.root 只能包含一个外部配置路径(对于我的要求,这就足够了)与 spring.config.location 相比,其中可以指定多个逗号分隔的路径
  • SpringApplicationBuilder.properties(...) 设置应用程序的默认属性。因此,无法再从外部指定 spring.config.location,因为 JVM 或 JNDI 属性优先于默认属性,因此会再次覆盖 spring.config.location