基本处理流程
BootstrapApplicationListener
这个是springcloud
中的自动配置监听器之一,这个就是可以做远程配置的。
而且他排序在ConfigFileApplicationListener
前面的,这个是要点,因为ConfigFileApplicationListener
会进行文件的加载,如果我想添加一些新的配置文件,就可以在BootstrapApplicationListener
中添加,比如bootstrap
配置文件就是这么做的。
onApplicationEvent
看起来好像没做多少东西,其实里面重新创建了一个SpringApplication
上下文呢,为了添加BootstrapImportSelectorConfiguration
配置类,里面会注册所有BootstrapConfiguration
类型的配置类。然后进行上下文的run
,ConfigFileApplicationListener
会去加载bootstrap
的配置文件,整合初始化器到新上下文,具体慢慢分析。
public static final String BOOTSTRAP_PROPERTY_SOURCE_NAME = "bootstrap";
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
true)) {//默认是true
return;
}
// 不会重复执行,如果有bootstrap属性名了就返回
if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
return;
}
ConfigurableApplicationContext context = null;
String configName = environment
.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
.getInitializers()) {//从父上下文初始化器里获取
if (initializer instanceof ParentContextApplicationContextInitializer) {
context = findBootstrapContext(
(ParentContextApplicationContextInitializer) initializer,
configName);
}
}
if (context == null) {
context = bootstrapServiceContext(environment, event.getSpringApplication(),
configName);
event.getSpringApplication()
.addListeners(new CloseContextOnFailureApplicationListener(context));
}
apply(context, event.getSpringApplication(), environment);
}
bootstrapServiceContext创建新上下文一
一般没有父上下文初始化,所以要重新创建一个上下文,为的就是来加载一些配置文件。
首先是创建一个新的环境,将里面的属性源删除干净,然后放入spring.config.name=bootstrap
的属性源,如果有spring.config.location
和spring.config.additional-location
也一起放入,封装成一个MapPropertySource
属性源name
是bootstrap
,放进新环境属性源里,然后把老的环境属性源放入到新的里。
//初始化一个上下文
private ConfigurableApplicationContext bootstrapServiceContext(
ConfigurableEnvironment environment, final SpringApplication application,
String configName) {
StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
MutablePropertySources bootstrapProperties = bootstrapEnvironment
.getPropertySources();
for (PropertySource<?> source : bootstrapProperties) {//删除干净
bootstrapProperties.remove(source.getName());
}
String configLocation = environment
.resolvePlaceholders("${spring.cloud.bootstrap.location:}");
String configAdditionalLocation = environment
.resolvePlaceholders("${spring.cloud.bootstrap.additional-location:}");
Map<String, Object> bootstrapMap = new HashMap<>();
//添加配置名bootstrap
bootstrapMap.put("spring.config.name", configName);
bootstrapMap.put("spring.main.web-application-type", "none");
if (StringUtils.hasText(configLocation)) {
bootstrapMap.put("spring.config.location", configLocation);
}
if (StringUtils.hasText(configAdditionalLocation)) {
bootstrapMap.put("spring.config.additional-location",
configAdditionalLocation);
}
bootstrapProperties.addFirst(
new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
for (PropertySource<?> source : environment.getPropertySources()) {
if (source instanceof StubPropertySource) {
continue;
}
bootstrapProperties.addLast(source);//老的放进新的里
}
bootstrapServiceContext创建新上下文二
创建一个SpringApplicationBuilder
,就是建造者模式,里面就是创建SpringApplication
的,然后设置一些属性,是一个最简单的一半上下文设置,然后设置一个配置文件BootstrapImportSelectorConfiguration
。
SpringApplicationBuilder builder = new SpringApplicationBuilder()
.profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
.environment(bootstrapEnvironment)
// Don't use the default properties in this builder
.registerShutdownHook(false).logStartupInfo(false)
.web(WebApplicationType.NONE);
final SpringApplication builderApplication = builder.application();
if (builderApplication.getMainApplicationClass() == null) {
builder.main(application.getMainApplicationClass());
}
if (environment.getPropertySources().contains("refreshArgs")) {
builderApplication
.setListeners(filterListeners(builderApplication.getListeners()));
}
builder.sources(BootstrapImportSelectorConfiguration.class);
所以等于创建了一个普通的新上下文啦。
bootstrapServiceContext创建新上下文三
SpringApplicationBuilder
的run
方法:
最终还是调用SpringApplication
的run
,但是里面就简单的做了一件事,注册我们的BootstrapImportSelectorConfiguration
配置文件,具体我们下篇说吧。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。