【问题标题】:Externalizing configuration in Spring Boot with multiple applications running in the same container在同一个容器中运行多个应用程序的 Spring Boot 中的外部化配置
【发布时间】:2017-10-23 22:56:50
【问题描述】:

我正在构建多个 Spring Boot 应用程序,它们将部署在同一个 servlet 容器上。但是我很难让 Spring Boot 以我想要的方式处理外部化配置文件,而不是像框架想要的那样。

情况:

  • 多个 Spring Boot 应用程序将部署在单个 servlet 容器(WAR 文件)上
  • 配置文件的位置将通过JVM属性spring.config.location设置
  • 嵌入式部署不是一种选择

问题:

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

我想要什么:

  • 无需设置spring.config.name,因为配置名称应在我们所有应用程序中标准化(常量)
  • 外部化配置属性应覆盖我部署的 WAR 中打包的 application.properties 中的值
  • 配置文件特定配置(应用程序-{profile})应该是可能的
  • 代码中没有硬编码的配置位置
  • 在每个应用程序目录布局中组织配置文件:

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

问题:

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

还有其他方法可以得到想要的结果吗?

【问题讨论】:

    标签: java spring-boot configuration war


    【解决方案1】:

    您可以使用@PropertySource 实现您的目标。根据官方文档(Externalized Configuration),你可以使用这个注解来外部化配置文件,例如:

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

    here 中所述,在@PropertySource 内,您可以使用将针对其他属性源解析的占位符,例如application.properties中声明的值

    假设“my.placeholder”存在于已注册的属性源之一中,例如系统属性或环境变量,占位符会被解析为对应的值。如果不是,则“默认/路径”将用作默认值。表示默认值(由冒号“:”分隔)是可选的。如果未指定默认值并且无法解析属性,则会抛出 IllegalArgumentException。

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

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

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

    为了使用 PropertySource 中的属性解析 bean 定义或 @Value 注释中的 ${...} 占位符,必须注册一个 PropertySourcesPlaceholderConfigurer。这在 XML 中使用时会自动发生,但在使用 @Configuration 类时必须使用静态 @Bean 方法显式注册。

    更新:

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

    spring.profiles.active=external
    

    在位于"${properties_home}/${application_id}/application.properties" 的文件中声明您希望优先作为外部配置文件的一部分的所有属性。

    【讨论】:

    • 我喜欢使用占位符作为属性源值的方法。但是有几个限制:我不能使用 Spring Boot 对配置文件所做的额外糖,比如配置文件后缀或不同的配置格式(属性、yml)。另一个问题是 @PropertySource 实际上并没有覆盖我在打包的 WAR 文件中的 application.properties 中指定的默认值。似乎是这样,因为根据文档,PropertySources 位于优先级链中的应用程序配置文件下方。
    • 1.您能否详细说明以下语句是什么意思“我不能使用 Spring Boot 对配置文件所做的额外糖,例如配置文件后缀或不同的配置格式(属性、yml)”。 2 您没有在原始问题中指定要覆盖打包的 application.properties 中的值。
    • 1.我想说的是,默认情况下 Spring Boot 不仅会找到文件“application.properties”,还会找到文件“application-{profile}.properties”或“application.yml”。 2. 是的,我的错。我忘了提它,因为我认为这是外部化配置最常见的用例。
    • 我已更新我的回复以实现 (2)。这只是一种方法,其他方法是通过 JNDI、ServletContext 等。请参阅文档中的完整列表。使用弹簧型材是最简单的方法。目前尚不清楚您要对 (1) 或原始问题中的更新详细信息说什么 - “配置文件特定配置 (application-{profile}) 应该是可能的”。
    【解决方案2】:

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

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

    @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

    【讨论】:

      猜你喜欢
      • 2014-11-10
      • 2021-12-15
      • 2021-12-16
      • 2019-07-28
      • 2015-07-26
      • 2022-09-23
      • 2015-05-20
      • 2021-11-16
      • 2018-06-20
      相关资源
      最近更新 更多