如何管理共享库中的 spring-cloud bootstrap 属性?
how to manage spring-cloud bootstrap properties in a shared library?
我正在构建一个库,它为使用我们的 Spring Cloud Config/Eureka
设置的应用程序提供了一个自以为是的配置。我们的想法是将此配置作为自定义启动器提供,在单个微服务应用程序中很少或没有 spring 与云相关的样板文件。
此时,我想放入此库的大部分共享配置都包含 bootstrap.yml
中的内容。我想在我的自定义启动器中提供 bootstrap.yml
,但使用该库的应用程序仍然需要能够提供它们自己的 bootstrap.yml
,即使只是这样它们才能正确设置它们的 spring.application.name .
由于 bootstrap.yml
从类路径加载的方式,如果应用程序有自己的 bootstrap.yml
,Spring 似乎会忽略共享库中的那个。由于 bootstrap 上下文对待 ApplicationContextInitializers
.
的特殊方式,我什至不能使用 ApplicationContextInitializer
来自定义环境
有人对适用于此的方法有任何建议吗?我想提供一个嵌入式库,使我们固执己见的 bootstrap 配置无需在我们所有项目中复制样板 bootstrap.yml
。
我找到了解决方法。此解决方案的目标是:
- 从共享库中的 yaml 文件加载值。
- 允许使用该库的应用程序引入它们自己的 bootstrap.yml,该库也加载到环境中。
- bootstrap.yml 中的值应覆盖共享 yaml 中的值。
主要挑战是在应用程序生命周期的适当时间点注入一些代码。具体来说,我们需要在将 bootstrap.yml PropertySource 添加到环境之后(以便我们可以以相对于它的正确顺序注入我们的自定义 PropertySource),而且在应用程序开始配置 bean 之前(作为我们的配置价值观控制行为)。
我找到的解决方案是使用自定义 EnvironmentPostProcessor
public class CloudyConfigEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
private YamlPropertySourceLoader loader;
public CloudyConfigEnvironmentPostProcessor() {
loader = new YamlPropertySourceLoader();
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication application) {
//ensure that the bootstrap file is only loaded in the bootstrap context
if (env.getPropertySources().contains("bootstrap")) {
//Each document in the multi-document yaml must be loaded separately.
//Start by loading the no-profile configs...
loadProfile("cloudy-bootstrap", env, null);
//Then loop through the active profiles and load them.
for (String profile: env.getActiveProfiles()) {
loadProfile("cloudy-bootstrap", env, profile);
}
}
}
private void loadProfile(String prefix, ConfigurableEnvironment env, String profile) {
try {
PropertySource<?> propertySource = loader.load(prefix + (profile != null ? "-" + profile: ""), new ClassPathResource(prefix + ".yml"), profile);
//propertySource will be null if the profile isn't represented in the yml, so skip it if this is the case.
if (propertySource != null) {
//add PropertySource after the "applicationConfigurationProperties" source to allow the default yml to override these.
env.getPropertySources().addAfter("applicationConfigurationProperties", propertySource);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public int getOrder() {
//must go after ConfigFileApplicationListener
return Ordered.HIGHEST_PRECEDENCE + 11;
}
}
此自定义 EnvironmentPostProcessor 可以通过 META-INF/spring.factories:
注入
#Environment PostProcessors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.mycompany.cloudy.bootstrap.autoconfig.CloudyConfigEnvironmentPostProcessor
有几点需要注意:
- YamlPropertySourceLoader 按配置文件加载 yaml 属性,因此如果您使用的是多文档 yaml 文件,您实际上需要从中单独加载每个配置文件,包括无配置文件配置。
- ConfigFileApplicationListener 是 EnvironmentPostProcessor,负责将 bootstrap.yml(或常规上下文的 application.yml)加载到环境中,因此为了相对于 [=41= 正确定位自定义 yaml 属性] 属性优先级,您需要在 ConfigFileApplicationListener 之后订购自定义 EnvironmentPostProcessor。
编辑:我最初的回答没有用。我正在用这个替换它,确实如此。
您可以使用 META-INF/spring.factories
文件中的 org.springframework.cloud.bootstrap.BootstrapConfiguration
键将共享库中的 PropertySource 添加到 bootstrap 属性。
例如,您可以创建一个包含以下内容的库:
src/main/java/com/example/mylib/MyLibConfig.java
package com.example.mylib;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:mylib-config.properties")
public class MyLibConfig {
}
src/main/resources/mylib-config.properties
eureka.instance.public=true
# or whatever...
src/main/resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.example.mylib.MyLibConfig
更多详情:http://projects.spring.io/spring-cloud/spring-cloud.html#_customizing_the_bootstrap_configuration
我正在构建一个库,它为使用我们的 Spring Cloud Config/Eureka
设置的应用程序提供了一个自以为是的配置。我们的想法是将此配置作为自定义启动器提供,在单个微服务应用程序中很少或没有 spring 与云相关的样板文件。
此时,我想放入此库的大部分共享配置都包含 bootstrap.yml
中的内容。我想在我的自定义启动器中提供 bootstrap.yml
,但使用该库的应用程序仍然需要能够提供它们自己的 bootstrap.yml
,即使只是这样它们才能正确设置它们的 spring.application.name .
由于 bootstrap.yml
从类路径加载的方式,如果应用程序有自己的 bootstrap.yml
,Spring 似乎会忽略共享库中的那个。由于 bootstrap 上下文对待 ApplicationContextInitializers
.
ApplicationContextInitializer
来自定义环境
有人对适用于此的方法有任何建议吗?我想提供一个嵌入式库,使我们固执己见的 bootstrap 配置无需在我们所有项目中复制样板 bootstrap.yml
。
我找到了解决方法。此解决方案的目标是:
- 从共享库中的 yaml 文件加载值。
- 允许使用该库的应用程序引入它们自己的 bootstrap.yml,该库也加载到环境中。
- bootstrap.yml 中的值应覆盖共享 yaml 中的值。
主要挑战是在应用程序生命周期的适当时间点注入一些代码。具体来说,我们需要在将 bootstrap.yml PropertySource 添加到环境之后(以便我们可以以相对于它的正确顺序注入我们的自定义 PropertySource),而且在应用程序开始配置 bean 之前(作为我们的配置价值观控制行为)。
我找到的解决方案是使用自定义 EnvironmentPostProcessor
public class CloudyConfigEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
private YamlPropertySourceLoader loader;
public CloudyConfigEnvironmentPostProcessor() {
loader = new YamlPropertySourceLoader();
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication application) {
//ensure that the bootstrap file is only loaded in the bootstrap context
if (env.getPropertySources().contains("bootstrap")) {
//Each document in the multi-document yaml must be loaded separately.
//Start by loading the no-profile configs...
loadProfile("cloudy-bootstrap", env, null);
//Then loop through the active profiles and load them.
for (String profile: env.getActiveProfiles()) {
loadProfile("cloudy-bootstrap", env, profile);
}
}
}
private void loadProfile(String prefix, ConfigurableEnvironment env, String profile) {
try {
PropertySource<?> propertySource = loader.load(prefix + (profile != null ? "-" + profile: ""), new ClassPathResource(prefix + ".yml"), profile);
//propertySource will be null if the profile isn't represented in the yml, so skip it if this is the case.
if (propertySource != null) {
//add PropertySource after the "applicationConfigurationProperties" source to allow the default yml to override these.
env.getPropertySources().addAfter("applicationConfigurationProperties", propertySource);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public int getOrder() {
//must go after ConfigFileApplicationListener
return Ordered.HIGHEST_PRECEDENCE + 11;
}
}
此自定义 EnvironmentPostProcessor 可以通过 META-INF/spring.factories:
注入#Environment PostProcessors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.mycompany.cloudy.bootstrap.autoconfig.CloudyConfigEnvironmentPostProcessor
有几点需要注意:
- YamlPropertySourceLoader 按配置文件加载 yaml 属性,因此如果您使用的是多文档 yaml 文件,您实际上需要从中单独加载每个配置文件,包括无配置文件配置。
- ConfigFileApplicationListener 是 EnvironmentPostProcessor,负责将 bootstrap.yml(或常规上下文的 application.yml)加载到环境中,因此为了相对于 [=41= 正确定位自定义 yaml 属性] 属性优先级,您需要在 ConfigFileApplicationListener 之后订购自定义 EnvironmentPostProcessor。
编辑:我最初的回答没有用。我正在用这个替换它,确实如此。
您可以使用 META-INF/spring.factories
文件中的 org.springframework.cloud.bootstrap.BootstrapConfiguration
键将共享库中的 PropertySource 添加到 bootstrap 属性。
例如,您可以创建一个包含以下内容的库:
src/main/java/com/example/mylib/MyLibConfig.java
package com.example.mylib;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:mylib-config.properties")
public class MyLibConfig {
}
src/main/resources/mylib-config.properties
eureka.instance.public=true
# or whatever...
src/main/resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.example.mylib.MyLibConfig
更多详情:http://projects.spring.io/spring-cloud/spring-cloud.html#_customizing_the_bootstrap_configuration