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

sha*_*bot 5 spring spring-boot spring-cloud netflix-eureka

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

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

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

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

meg*_*lop 6

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

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

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 {
}
Run Code Online (Sandbox Code Playgroud)

src/main/resources/mylib-config.properties

eureka.instance.public=true
# or whatever...
Run Code Online (Sandbox Code Playgroud)

src/main/resources/META-INF/spring.factories

org.springframework.cloud.bootstrap.BootstrapConfiguration=com.example.mylib.MyLibConfig
Run Code Online (Sandbox Code Playgroud)

更多详情:http : //projects.spring.io/spring-cloud/spring-cloud.html#_customizing_the_bootstrap_configuration


sha*_*bot 2

我能够找到解决方案。该解决方案的目标是:

  • 从共享库中的 yaml 文件加载值。
  • 允许使用该库的应用程序引入自己的 bootstrap.yml,该 bootstrap.yml 也加载到环境中。
  • bootstrap.yml 中的值应覆盖共享 yaml 中的值。

主要挑战是在应用程序生命周期的适当时刻注入一些代码。具体来说,我们需要在 bootstrap.yml PropertySource 添加到环境之后(以便我们可以按照相对于它的正确顺序注入自定义 PropertySource),但也要在应用程序开始配置 beans 之前执行此操作(因为我们的配置值控制行为)。

我找到的解决方案是使用自定义的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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

#Environment PostProcessors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.mycompany.cloudy.bootstrap.autoconfig.CloudyConfigEnvironmentPostProcessor
Run Code Online (Sandbox Code Playgroud)

有几点需要注意:

  • YamlPropertySourceLoader 按配置文件加载 yaml 属性,因此,如果您使用多文档 yaml 文件,则实际上需要分别从中加载每个配置文件,包括无配置文件配置。
  • ConfigFileApplicationListener 是环境后处理器,负责将 bootstrap.yml(或常规上下文的 application.yml)加载到环境中,因此为了相对于 bootstrap.yml 属性优先顺序正确定位自定义 yaml 属性,您需要对您的ConfigFileApplicationListener 之后的自定义 EnvironmentPostProcessor。

编辑:我最初的答案不起作用。我把它换成这个,确实如此。