首页 文章

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

提问于
浏览
2

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

Situation:

  • 多个Spring Boot应用程序将部署在单个servlet容器(WAR文件)中

  • 配置文件的位置将通过JVM属性 spring.config.location 设置

  • 嵌入式部署不是一种选择

Problem:

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

What I would like:

  • 无需设置 spring.config.name ,因为配置名称应该在所有应用程序中标准化(常量)

  • 外部化配置属性应覆盖在已部署的WAR中打包的application.properties中的值
    应该可以使用

  • 配置文件特定配置(application-

  • 代码中没有硬编码的配置位置

  • 在每个应用程序目录布局中组织配置文件:

$ /app1/application.properties $ /app2/application.properties $ /app3/application.properties

Questions:

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

是否有其他方法可以获得理想的结果?

2 回答

  • 0

    您可以使用 @PropertySource 实现您正在尝试的功能 . 根据官方文档(Externalized Configuration),您可以使用此批注来外部化配置文件,例如:

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

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

    假设“my.placeholder”存在于已注册的其中一个属性源中,例如系统属性或环境变量,占位符将被解析为相应的值 . 如果没有,则“default / path”将用作默认值 . 表示默认值(由冒号“:”分隔)是可选的 . 如果未指定缺省值且无法解析属性,则将抛出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方法显式注册 .

    Update:

    要覆盖外部文件中的属性,可以使用 spring 配置文件 . 在打包的application.properties中,您需要设置:

    spring.profiles.active=external
    

    声明要作为 "${properties_home}/${application_id}/application.properties" 中文件内部外部配置文件的一部分优先使用的所有属性 .

  • 2

    @Iulian Rosca使用像_1667299这样的模式的建议让我想到定义一个自定义JVM属性,如 app.config.root ,并在应用程序生命周期的早期使用此属性覆盖 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 .

相关问题