如何在共享库中管理 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() 的解析位置?