我能找到解決方案。此解決方案的目標是:
- 從共享庫中的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是負責將bootstrap.yml(或常規上下文的application.yml)加載到環境中的EnvironmentPostProcessor,因此爲了優先定位相對於bootstrap.yml屬性的自定義yaml屬性,您需要在ConfigFileApplicationListener之後訂購您的定製EnvironmentPostProcessor。
編輯:我的初步答案沒有奏效。我用這個替換它,這樣做。
我不認爲你可以用bootstrap.yml自己做,但你可以插入引導機制本身並使用默認值填充屬性源。 – spencergibb
爲什麼是yaml文件?您可以創建Java配置。這將更容易分發。 –
當然java會更容易分發。不過,我需要做大量的定製才能完成yaml可以非常容易地完成的任務。例如,簡單地提供一些javaconfig來關閉某個配置文件下的spring cloud bus,在配置方面比慣例更令人生畏,但是可以通過簡單的spring.cloud.bus.enabled = false在yaml中完成。只是爲了提供默認的eureka defaultZone,我正在尋找自己配置bean,否則自動配置會受益。 – shazbot