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

Posted

技术标签:

【中文标题】如何在共享库中管理 spring-cloud 引导属性?【英文标题】:how to manage spring-cloud bootstrap properties in a shared library? 【发布时间】:2016-10-19 16:26:26 【问题描述】:

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

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

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

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

【问题讨论】:

我不认为你可以使用 bootstrap.yml 本身来做到这一点,但你可以插入引导机制本身并使用默认值填充属性源。 为什么是 yaml 文件?您可以创建 Java 配置。这会更容易分发。 当然 java 会更容易分发。但是,我需要进行大量定制才能完成使用 yaml 可以轻松完成的事情。例如,简单地提供一些 javaconfig 来关闭某个配置文件下的 spring 云总线,在配置超过约定方面是相当令人生畏的,但可以在 yaml 中通过简单的 spring.cloud.bus.enabled=false 来完成。只是为了提供一个默认的 eureka defaultZone,我正在考虑自己配置 bean,否则它们会从 autoconfig 中受益。 【参考方案1】:

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

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

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 

src/main/resources/mylib-config.properties

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

src/main/resources/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

【讨论】:

【参考方案2】:

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

从共享库中的 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,因此为了正确定位自定义 yaml 属性相对于 bootstrap.yml 属性的优先级,您需要在 ConfigFileApplicationListener 之后订购您的自定义 EnvironmentPostProcessor。

编辑:我最初的回答无效。我正在用这个替换它。

【讨论】:

以上是关于如何在共享库中管理 spring-cloud 引导属性?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Cloud、Hystrix 和 JPA - LazyInitializationException

如何在运行时确定共享库中全局变量的地址范围?

如何在共享库中找到 C++ isfinite() 的解析位置?

如何使用 GDB 调试共享对象库中的函数?

如何在 Git proto 存储库中发布对共享 .proto 文件的更改?

如何在共享库中获取正确的函数名?