文章目录
- 初始化
SpringBoot启动类:
@SpringBootApplication
public class AppRun {public static void main(String[] args) {SpringApplication.run(AppRun.class, args);}
}
步入SpringApplication.run(AppRun.class, args)
方法:
这里分为两步:
- 创建一个SpringApplication实例:初始化一些配置(包括初始化对象和监听器以及一些配置文件)
- 调用run方法。
new SpringApplication(primarySources).run(args)
初始化
步入SpringApplication的构造方法中:
首先获取资源加载器、保存primarySources属性、web类型,设置初始化器和监听器,获取main方法所在的类
重点看一下获取初始化器和监听器这部分。
在此之前,看一下271行的代码:
在SpringBoot的老版本中,是没有这快代码的,这里主要是提前加载一些初始化器、监听器和其他配置放入缓存中,以便后续获取。
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
步入getSpringFactoriesInstances
方法中:
最终来到这里:这里首先构造一个加载器,再去调用load方法。
步入forDefaultResourceLocation方法:
最终来到这里:
注意332行代码:如果loaders这个map中有resourceLacation,则返回该key值对应的value。
当然,这里显然是没有的。所以会加载后面的函数,存入loaders中,并返回该值。
先看看loadFactoriesResource方法做了什么:
首先将项目中含有META-INFO/spring.factories
的文件路径加载出来,这里有2个url,一个是autoconfigrition下的,一个是aop下的。
处理完之后去重。
最后收集到18个,包括初始化器和监听器等。
紧接着调用Collections.unmodifiableMap(result)
方法。
看看Collections.unmodifiableMap(result)
这个方法:
最后将map存入m这个属性中。
分析完SpringFactoriesLoader的参数了,来看看它的构造方法吧:
这样,factories就存入了我们加载出来的类。
构建完加载器,回去调用这个load方法:
步入loadFactoryNames方法:
最后会在m这个缓存中取值。
当然这里什么都没有,最后返回null。
回到最初这里:
后面两行代码,应该就很清晰了,因为调用的都是同一个getSpringFactoriesInstances
方法,因为前者已经加载完配置文件,所以后面这里设置初始化器和监听器会从我们设置好的那个m缓存中获取。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
值得注意的是,再次从m这个缓存中获取的时候,我们会取到值,那么这个for循环就会执行:
这里首先会通过反射创建该对象的实例,再add到result的List集合中。