Springboot解析--1、初始化器部分

98 阅读1分钟

一、核心问题

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