1. 前言
本文基于Spring Cloud Version:Spring Cloud Hoxton.SR8,Spring Boot Version:2.3.2.RELEASE
在spring boot中Environment的扩展配置可借助ConfigFileApplicationListener这个ApplicationListener,通过自定义类实现EnvironmentPostProcessor接口来扩展,详细介绍可以我之前的文章《spring boot参数配置之Environment源码分析》、《spring boot参数配置之Environment扩展》.
在spring cloud中Environment的扩展配置还可以借助PropertySourceBootstrapConfiguration这个ApplicationContextInitializer,通过自定义类实现PropertySourceLocator接口来扩展。
2. spring cloud 启动处理Environment源码分析
2.1. spring cloud 启动ApplicationContext两阶段创建
在spring cloud中启动时SpringApplication.run(String... args)会执行两次,也就是说ApplicationContext会分为两阶段来创建。
-
第一次执行run(阶段一):阶段一执行会只会加载
bootstrap.yml里配置的参数以及创建spring.factories中org.springframework.cloud.bootstrap.BootstrapConfiguration里配置的类,这些类往往是一些跟配置相关的类,这一阶段创建的类优先级很高,主要为阶段二ApplicationContext里需要创建的类提供一些准备。
可以看看spring-cloud-context-2.2.5.RELEASE.jar里的spring.factories中# Bootstrap components相关配置 -
第二次执行run(阶段二):阶段二执行会加载剩余所有的参数以及创建所有的bea对象,主要是通过@ComponentScan可以扫描到的、xml里配置的bean、以及通过
@EnableAutoConfiguration加载spring.factories里的org.springframework.boot.autoconfigure.EnableAutoConfiguration的相关配置
可以看看 spring-cloud-context-2.2.5.RELEASE.jar里的spring.factories中# AutoConfiguration相关配置
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener
# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.cloud.util.random.CachedRandomPropertySourceAutoConfiguration
2.2. spring cloud 启动参数相关源码分析
主线:PropertySourceBootstrapConfiguration的initialize(…)->PropertySourceLocator.locate()
核心源码如下:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//environment参数创建准备工作
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
//这里触发再一次执行上面的run方法,也就是出发第一阶段applicationContest创建的创建
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
…………
}
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
这个代码的详细分析可以参见文章《spring boot参数配置之Environment源码分析》。
PropertySourceBootstrapConfiguration的创建
阶段一在refreshContext之前,SpringApplication中所有的initializers截图如下,并没有PropertySourceBootstrapConfiguration。

从上面spring-cloud-context-2.2.5.RELEASE.jar里的spring.factories的配置有org.springframework.cloud.bootstrap.BootstrapConfiguration=\org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,所以在第一阶段执行完后,SpringApplication中所有的initializers截图如下,以包含PropertySourceBootstrapConfiguration。
这一阶段同样需要创建自定义的PropertySourceLocator对象,如:NacosPropertySourceLocator实现类,其配置如下:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
PropertySourceBootstrapConfiguration的initialize(…)->PropertySourceLocator.locate()执行
阶段二的applyInitializers方法会调用PropertySourceBootstrapConfiguration的initialize方法,核心代码如下:
public void initialize(ConfigurableApplicationContext applicationContext) {
List<PropertySource<?>> composite = new ArrayList<>();
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySourceLocator locator : this.propertySourceLocators) {
Collection<PropertySource<?>> source = locator.locateCollection(environment);
if (source == null || source.size() == 0) {
continue;
}
List<PropertySource<?>> sourceList = new ArrayList<>();
for (PropertySource<?> p : source) {
if (p instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) p;
sourceList.add(new BootstrapPropertySource<>(enumerable));
}
else {
sourceList.add(new SimpleBootstrapPropertySource(p));
}
}
logger.info("Located property source: " + sourceList);
composite.addAll(sourceList);
empty = false;
}
if (!empty) {
MutablePropertySources propertySources = environment.getPropertySources();
String logConfig = environment.resolvePlaceholders("${logging.config:}");
LogFile logFile = LogFile.get(environment);
for (PropertySource<?> p : environment.getPropertySources()) {
if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
propertySources.remove(p.getName());
}
}
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment);
}
}
核心逻辑就是遍历所有propertySourceLocators执行其locate(……)方法,将自定义加载的CompositePropertySource然后追加到spring中的environment中。
2.3. 自定义PropertySourceLocator扩展environment实例
PropertySourceLocator实现如下:
public class CustPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
//可以从自己的配置中心获取数据
Map<String, Object> configs =new HashMap<>();
configs.put("metric.post.url","http://baidu.com");
return new MapPropertySource("MY_CONFIG_CENTER",configs);
}
}
spring.factories配置如下:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.nacoshttpproducer.configure.CustPropertySourceLocator
本文基于Spring Cloud Hoxton.SR8和Spring Boot 2.3.2.RELEASE,探讨了如何在spring cloud中自定义扩展Environment配置。通过两阶段创建ApplicationContext,分析了启动过程中的Environment源码,介绍了如何在阶段一和阶段二加载自定义配置,并提供了自定义扩展Environment的实例和配置方法。
1989

被折叠的 条评论
为什么被折叠?



