重写spring cloud config 本地bootstrap
在spring-cloud中使用了config-server之后,需要在client端加入bootstrap作为配置文件,其中通常包含如下:
spring.application.name=ms-asset spring.cloud.config.label=master spring.cloud.config.profile=test spring.cloud.config.uri=http://ms-config-server-srv:8001/
但是这样的配置存在问题,因其固定了使用的配置环境和label,如采用Docker部署,则无法通过环境变量更改,通过阅读源码可知,Spring-cloud 通过两个JVM参数控制加载的配置文件。
-Dspring.cloud.config.label=master
-Dspring.cloud.config.profile=test
其中label表示分支,profile表示加载的配置环境。
其源码非常简单,在ConfigClientProperties中,如下所示:
public ConfigClientProperties override( org.springframework.core.env.Environment environment) { ConfigClientProperties override = new ConfigClientProperties(); BeanUtils.copyProperties(this, override); override.setName( environment.resolvePlaceholders("${" + ConfigClientProperties.PREFIX + ".name:${spring.application.name:application}}")); if (environment.containsProperty(ConfigClientProperties.PREFIX + ".profile")) { override.setProfile( environment.getProperty(ConfigClientProperties.PREFIX + ".profile")); } if (environment.containsProperty(ConfigClientProperties.PREFIX + ".label")) { override.setLabel( environment.getProperty(ConfigClientProperties.PREFIX + ".label")); } return override; }
可以看出,spring cloud仅支持profile和label这两个配置注入,在一般情况下足够用了。
另外存在一种修改spring-boot配置文件的方式,原理是监测spring初始化完成的事件,然后将环境变量注入配置中,可用于覆盖spring cloud config server的统一配置,但由于bootstrap处在加载链的最前端,在初始化之前即以完成的远程配置文件的加载,因此该方法无效,一并贴出,有缘人自取。
package com.example; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; @Component @Order(Ordered.HIGHEST_PRECEDENCE) public class ConfigServicePropertyDeprioritizer implements ApplicationListener<ApplicationPreparedEvent> { private static final String CONFIG_SOURCE = "bootstrap"; private static final String PRIORITY_SOURCE = "systemEnvironment"; @Override public void onApplicationEvent(ApplicationPreparedEvent event) { ConfigurableEnvironment environment = event.getApplicationContext() .getEnvironment(); MutablePropertySources sources = environment.getPropertySources(); PropertySource<?> bootstrap = findSourceToMove(sources); if (bootstrap != null) { sources.addAfter(PRIORITY_SOURCE, bootstrap); } } private PropertySource<?> findSourceToMove(MutablePropertySources sources) { boolean foundPrioritySource = false; for (PropertySource<?> source : sources) { if (PRIORITY_SOURCE.equals(source.getName())) { foundPrioritySource = true; continue; } if (CONFIG_SOURCE.equals(source.getName())) { // during bootstrapping, the "bootstrap" PropertySource // is a simple MapPropertySource, which we don't want to // use, as it's eventually removed. The real values will // be in a CompositePropertySource if (source instanceof CompositePropertySource) { return foundPrioritySource ? null : source; } } } return null; } }