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

Java 通过在同一容器中运行多个应用程序在Spring Boot中外部化配置,java,spring-boot,configuration,war,Java,Spring Boot,Configuration,War,我正在构建多个Spring引导应用程序,这些应用程序将部署在同一个servlet容器上。但是我很难让Spring Boot以我想要的方式使用外部化的配置文件,而且不像框架想要的那样 情况: 将在单个servlet容器(WAR文件)上部署多个Spring引导应用程序 配置文件的位置将通过JVM属性spring.config.location 嵌入式部署不是一个选项 问题: 由于应用程序部署在同一个JVM上,因此属性spring.config.location对于所有应用程序都具有相同的值。我希

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

情况:

  • 将在单个servlet容器(WAR文件)上部署多个Spring引导应用程序
  • 配置文件的位置将通过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

问题:

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


是否有其他方法可以获得所需的结果?

您可以通过使用
@PropertySource
实现您正在尝试的目标。根据官方文档(),您可以使用此注释将配置文件外部化,例如:

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

 }
如中所述,在
@PropertySource
中,您可以使用占位符,这些占位符将根据其他属性源进行解析,例如
应用程序中声明的值。properties

假设“my.placeholder”出现在已注册的某个属性源中,例如系统属性或环境变量,则占位符将解析为相应的值。如果不是,则“默认/路径”将用作默认值。表示默认值(以冒号分隔):)是可选的。如果未指定默认值且无法解析属性,则将引发IllegalArgumentException

您可以将
properties\u home
声明为环境变量,并在
application.properties
文件中声明
application\u 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\u home}/${application\u id}/application.properties”中的文件中声明您希望作为外部配置文件的一部分优先的所有属性。

建议@Iulian Rosca使用类似
${properties\u home}/${application\u id}的模式/application.properties
让我想到了定义一个自定义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

我喜欢使用占位符作为属性源值的方法。但是有几个限制:我不能使用SpringBoot对配置文件所做的额外功能,比如配置文件后缀或不同的配置格式(properties,yml)。另一个问题是@PropertySource实际上并没有覆盖我在打包WAR文件的application.properties中指定的默认值。这似乎是事实,因为根据文档,PropertySources位于优先级链中的应用程序配置文件之下。1。您能否详细说明以下语句的含义“我不能使用SpringBoot对配置文件(如配置文件后缀或不同的配置格式(properties,yml))所做的额外功能”。2您没有在原始问题中指定要覆盖打包应用程序中的值。属性。1。我想说的是,Spring引导在默认情况下不仅会找到文件“application.properties”,还会找到文件“application-{profile}.properties”或“application.yml”。2.是的,我的错。我忘记提了,因为我