spring boot 整合spring cloud config通过ApplicationEnvironmentPreparedEvent事件触发,新建bootstrap 上下文加载ApplicationContextInitializer给SpringApplication ,从而进行加载配置中心配置。
加载路径源码
加载主要核心入口BootstrapApplicationListener
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
监听ApplicationEnvironmentPreparedEvent事件
public class BootstrapApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
if ((Boolean)environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, true)) {
if (!environment.getPropertySources().contains("bootstrap")) {
ConfigurableApplicationContext context = null;
String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
Iterator var5 = event.getSpringApplication().getInitializers().iterator();
while(var5.hasNext()) {
ApplicationContextInitializer<?> initializer = (ApplicationContextInitializer)var5.next();
if (initializer instanceof ParentContextApplicationContextInitializer) {
context = this.findBootstrapContext((ParentContextApplicationContextInitializer)initializer, configName);
}
}
if (context == null) {
//构建bootstrap上下文容器加载 ApplicationContextInitializer
context = this.bootstrapServiceContext(environment, event.getSpringApplication(), configName);
event.getSpringApplication().addListeners(new ApplicationListener[]{new BootstrapApplicationListener.CloseContextOnFailureApplicationListener(context)});
}
this.apply(context, event.getSpringApplication(), environment);
}
}
}
//加载 ApplicationContextInitializer 到 SpringApplication
private void apply(ConfigurableApplicationContext context, SpringApplication application, ConfigurableEnvironment environment) {
List<ApplicationContextInitializer> initializers = this.getOrderedBeansOfType(context, ApplicationContextInitializer.class);
application.addInitializers((ApplicationContextInitializer[])initializers.toArray(new ApplicationContextInitializer[initializers.size()]));
this.addBootstrapDecryptInitializer(application);
}
BootstrapImportSelectorConfiguration 为bootstrap容器入口配置类
private ConfigurableApplicationContext bootstrapServiceContext(ConfigurableEnvironment environment, final SpringApplication application, String configName) {
...
builder.sources(new Class[]{BootstrapImportSelectorConfiguration.class});
ConfigurableApplicationContext context = builder.run(new String[0]);
context.setId("bootstrap");
this.addAncestorInitializer(application, context);
bootstrapProperties.remove("bootstrap");
this.mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
return context;
}
BootstrapImportSelectorConfiguration 导入BootstrapImportSelector类
@Import({BootstrapImportSelector.class})
public class BootstrapImportSelectorConfiguration {
public BootstrapImportSelectorConfiguration() {
}
}
加载BootstrapConfiguration配置的类,bootstrap容器的bean
public class BootstrapImportSelector implements EnvironmentAware, DeferredImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//加载BootstrapConfiguration注册bean
List<String> names = new ArrayList(SpringFactoriesLoader.loadFactoryNames(BootstrapConfiguration.class, classLoader));
names.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(this.environment.getProperty("spring.cloud.bootstrap.sources", ""))));
List<BootstrapImportSelector.OrderedAnnotatedElement> elements = new ArrayList();
Iterator var5 = names.iterator();
while(var5.hasNext()) {
String name = (String)var5.next();
try {
elements.add(new BootstrapImportSelector.OrderedAnnotatedElement(this.metadataReaderFactory, name));
} catch (IOException var8) {
}
}
AnnotationAwareOrderComparator.sort(elements);
String[] classNames = (String[])elements.stream().map((e) -> {
return e.name;
}).toArray((x$0) -> {
return new String[x$0];
});
return classNames;
}
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic
@interface BootstrapConfiguration {
Class<?>[] exclude() default {};
}
其中PropertySourceBootstrapConfiguration 为spring cloud config加载处理类
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
PropertySourceBootstrapConfiguration 实现 ApplicationContextInitializer接口 initialize函数加载配置
public class PropertySourceBootstrapConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
public void initialize(ConfigurableApplicationContext applicationContext) {
CompositePropertySource composite = new OriginTrackedCompositePropertySource("bootstrapProperties");
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Iterator var5 = this.propertySourceLocators.iterator();
while(var5.hasNext()) {
PropertySourceLocator locator = (PropertySourceLocator)var5.next();
PropertySource<?> source = null;
source = locator.locate(environment);
if (source != null) {
logger.info("Located property source: " + source);
composite.addPropertySource(source);
empty = false;
}
}
在prepareContext applyInitializers触发
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
PropertySourceLocator 接口
nacos和spring cloud config实现PropertySourceLocator接口
public interface PropertySourceLocator {
PropertySource<?> locate(Environment environment);
}
spring cloud config 实现ConfigServicePropertySourceLocator类
public class ConfigServicePropertySourceLocator implements PropertySourceLocator {
加载
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.config.client.ConfigServiceBootstrapConfiguration,\
public class ConfigServiceBootstrapConfiguration {
@Bean
@ConditionalOnMissingBean({ConfigServicePropertySourceLocator.class})
@ConditionalOnProperty(
value = {"spring.cloud.config.enabled"},
matchIfMissing = true
)
public ConfigServicePropertySourceLocator configServicePropertySource(ConfigClientProperties properties) {
ConfigServicePropertySourceLocator locator = new ConfigServicePropertySourceLocator(properties);
return locator;
}
nacos 实现 NacosPropertySourceLocator
public class NacosPropertySourceLocator implements PropertySourceLocator {
加载
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
public class NacosConfigBootstrapConfiguration {
@Bean
public NacosPropertySourceLocator nacosPropertySourceLocator(NacosConfigManager nacosConfigManager) {
return new NacosPropertySourceLocator(nacosConfigManager);
}
}
总结
1 PropertySourceLocator 接口是实现配置中心关键,开发者可以通过实现PropertySourceLocator 达到自定义配置
2 BootstrapConfiguration注解是bootstrap容器的扩展注册bean重要方式,通过spring.factories注册
3 通过配置中心加载过程可以了解到,spring boot 启动的时候,还有加载一个bootstrap容器的父容器,所以一些事件Listener监听器事件会触发两次。