使用在同一容器中运行的多个应用程序在Spring Boot中外部化配置
我正在构建多个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中的值
- 配置文件特定配置(application- {profile})应该是可能的
- 代码中没有硬编码的配置位置
-
在每个应用程序目录布局中组织配置文件:
$ {spring.config.location} /app1/application.properties $ {spring.config.location} /app2/application.properties $ {spring.config.location} /app3/application.properties
问题:
是否有某种机制来影响或覆盖外部配置文件的加载或解析?
是否有其他方法可以获得理想的结果?
您可以使用@PropertySource
实现您正在尝试的function。 根据官方文档( 外部化配置 ),您可以使用此批注外部化配置文件,例如:
@Configuration @PropertySource("file:/path/to/application.properties") public class AppConfig { }
如此处所述,在@PropertySource
您可以使用将针对其他属性源解析的占位符,例如在application.properties
声明的值
假设“my.placeholder”存在于已注册的其中一个属性源中,例如系统属性或环境变量,则占位符将被解析为相应的值。 如果没有,则“default / path”将用作默认值。 表示默认值(由冒号“:”分隔)是可选的。 如果未指定缺省值且无法解析属性,则将抛出IllegalArgumentException。
您可以在application.properties
文件中将properties_home
声明为环境变量和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"
文件中外部配置文件的一部分优先使用的所有属性。
@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 Properties优先于默认属性,因此会再次覆盖spring.config.location
。