2016-06-17 62 views
4

我正在建立一個庫,爲使用我們的Spring Cloud Config/Eureka安裝程序的應用程序提供自定義配置。我們的想法是將這種配置作爲自定義啓動程序提供,並在單獨的微服務應用程序中使用很少或沒有與彈簧雲相關的樣板。如何管理共享庫中的spring-cloud引導屬性?

在這一點上,我想放在這個庫中的大部分共享配置由bootstrap.yml中的東西組成。我想在我的自定義啓動器中提供bootstrap.yml,但使用該庫的應用程序仍然需要能夠提供自己的bootstrap.yml,即使只有這樣他們才能正確設置其spring.application.name。

由於從類路徑加載bootstrap.yml的方式,如果應用程序有自己的bootstrap.yml,Spring似乎忽略共享庫中的那個。我甚至無法使用ApplicationContextInitializer來定製環境,因爲引導程序上下文以特殊方式處理ApplicationContextInitializers

有沒有人有任何建議可以在這裏工作的方法?我想提供一個嵌入式庫,這使得我們有自信的引導配置工作,而無需在我們所有的項目中複製樣板bootstrap.yml

+3

我不認爲你可以用bootstrap.yml自己做,但你可以插入引導機制本身並使用默認值填充屬性源。 – spencergibb

+0

爲什麼是yaml文件?您可以創建Java配置。這將更容易分發。 –

+0

當然java會更容易分發。不過,我需要做大量的定製才能完成yaml可以非常容易地完成的任務。例如,簡單地提供一些javaconfig來關閉某個配置文件下的spring cloud bus,在配置方面比慣例更令人生畏,但是可以通過簡單的spring.cloud.bus.enabled = false在yaml中完成。只是爲了提供默認的eureka defaultZone,我正在尋找自己配置bean,否則自動配置會受益。 – shazbot

回答

1

我能找到解決方案。此解決方案的目標是:

  • 從共享庫中的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。

編輯:我的初步答案沒有奏效。我用這個替換它,這樣做。

1

您可以使用META-INF/spring.factories文件中的org.springframework.cloud.bootstrap.BootstrapConfiguration密鑰將共享庫中的PropertySource添加到引導屬性中。

例如,您可以創建一個包含以下內容的庫:

的src/main/JAVA/COM /例子/ 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 /資源/mylib-config.properties

eureka.instance.public=true 
# or whatever... 

的src /主/ RESOUR CES/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