如何在共享库中管理spring-cloud bootstrap属性?

时间:2016-06-17 18:37:42

标签: spring spring-boot spring-cloud netflix-eureka

我正在构建一个库,该库为使用我们Spring Cloud Config/Eureka设置的应用程序提供了一个固定的配置。我们的想法是将此配置作为自定义启动器提供,在单个微服务应用程序中很少或不使用与弹簧云相关的样板。

此时,我想要放在此库中的大部分共享配置都包含bootstrap.yml中的内容。我想在我的自定义启动器中提供bootstrap.yml,但使用该库的应用程序仍然需要能够提供自己的bootstrap.yml,即使这样他们也可以设置他们的spring.application。说得好。

由于从类路径加载bootstrap.yml的方式,如果应用程序有自己的bootstrap.yml,Spring似乎忽略了共享库中的那个。由于引导上下文处理ApplicationContextInitializer的特殊方式,我甚至无法使用ApplicationContextInitializers来自定义环境。

有没有人对此方法有效?我想提供一个drop-in lib,它使我们自以为是的bootstrap配置工作,而不必在所有项目中复制样板bootstrap.yml

2 个答案:

答案 0 :(得分:3)

您可以使用org.springframework.cloud.bootstrap.BootstrapConfiguration文件中的META-INF/spring.factories键将共享库中的PropertySource添加到引导程序属性中。

例如,您可以创建包含以下内容的库:

<强>的src /主/ 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 /主/资源/ mylib-config.properties

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

<强>的src /主/资源/ 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

答案 1 :(得分: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;
    }

}

可以通过META-INF / spring.factories注入此自定义EnvironmentPostProcessor:

#Environment PostProcessors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.mycompany.cloudy.bootstrap.autoconfig.CloudyConfigEnvironmentPostProcessor

有几点需要注意:

  • YamlPropertySourceLoader按配置文件加载yaml属性,因此如果您使用的是多文档yaml文件,则需要单独加载每个配置文件,包括无配置文件配置。
  • ConfigFileApplicationListener是EnvironmentPostProcessor,负责将bootstrap.yml(或常规上下文的application.yml)加载到Environment中,因此为了相对于bootstrap.yml属性正确定位自定义yaml属性,您需要在ConfigFileApplicationListener之后订购自定义的EnvironmentPostProcessor。

编辑:我的初步答案无效。我用这个代替了它。