一、核心问题
1、三种添加初始化器方式 参考:gitee:xuef:三种添加初始化器方式
2、Springboot是如何识别代码中定义的初始化器并加载进容器中的
3、加入到容器中的初始化器的调用点,即何时被调用?
二、初始化器的识别与加载
1、SPI方式(SpringFactoriesLoader)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//在这儿识别和加载初始化器的
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
1.1 this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
/**
先尝试缓存中查找类的全路径名,没有的话,会从所有jar中 找 META-INF/spring.factories 文件,
借助 PropertiesLoaderUtils.loadProperties(resource); 来读取文件中配置
*/
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//根据前一步获取的类的全路径名,创建类的实例。
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
1.2 调用点
org.springframework.boot.SpringApplication#run(java.lang.String...)
/**
在这儿 调用初始化器的 initialize()
protected void applyInitializers(ConfigurableApplicationContext context)
注意在调用之前会对定义的初始化的泛型进行检查,要求必须是 ConfigurableApplicationContext
*/
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
2 application.properties 配置方式的加载原理
TODO
DelegatingApplicationContextInitializer