如何管理共享库中的spring-cloud bootstrap属性? [英] how to manage spring-cloud bootstrap properties in a shared library?

查看:81
本文介绍了如何管理共享库中的spring-cloud bootstrap属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个库,该库为使用我们的Spring Cloud Config/Eureka设置的应用程序提供了合理的配置.想法是在单个微服务应用程序中以定制启动器的形式提供此配置,而几乎没有弹簧云相关的样板.

I'm in the process of building a library which provides an opinionated configuration for applications which use our Spring Cloud Config/Eureka setup. The idea is to deliver this configuration as a custom starter with little or no spring cloud-related boilerplate in individual microservice apps.

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

At this point, the majority of the shared configuration that I want to put in this library consists of stuff in bootstrap.yml. I'd like to provide bootstrap.yml in my custom starter, but applications using the library still need to be able to provide their own bootstrap.yml, even if only so they can set their spring.application.name properly.

由于从类路径加载bootstrap.yml的方式,如果应用程序具有自己的bootstrap.yml,Spring似乎会忽略共享库中的那个.由于引导上下文对待ApplicationContextInitializers的特殊方式,我什至不能使用ApplicationContextInitializer来定制环境.

Due to the way bootstrap.yml is loaded from the classpath, Spring seems to ignore the one in the shared lib if the application has its own bootstrap.yml. I can't even use an ApplicationContextInitializer to customize the Environment because of the special way the bootstrap context treats ApplicationContextInitializers.

有人对在这里可行的方法有任何建议吗?我想提供一个嵌入式库,使我们自以为是的引导程序配置能够工作,而不必在所有项目中都复制样板bootstrap.yml.

Does anyone have any recommendations for an approach that would work here? I want to provide a drop-in lib that makes our opinionated bootstrap config work without having to duplicate a boilerplate bootstrap.yml in all of our projects.

推荐答案

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

I was able to find a solution to this. The goals of this solution are:

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

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

The main challenge is to inject some code at the appropriate point in the application lifecycle. Specifically, we need to do it after the bootstrap.yml PropertySource is added to the environment (so that we can inject our custom PropertySource in the correct order relative to it), but also before the application starts configuring beans (as our config values control behavior).

我找到的解决方案是使用自定义的EnvironmentPostProcessor

The solution I found was to use a custom 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:

This custom EnvironmentPostProcessor can be injected via 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)加载到环境中,因此为了相对于bootstrap.yml属性正确地优先放置自定义yaml属性,您需要在ConfigFileApplicationListener之后订购自定义的EnvironmentPostProcessor.

我的最初答案无效.我要用这个代替它,

这篇关于如何管理共享库中的spring-cloud bootstrap属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆