SpringBoot总体流程
当我们启动一个SpringBoot程序的时候,只需要一个main方法就可以启动,但是对于其中流程时如何执行的,以及如何调用spring的IOC和AOP机制,本篇带着这个问题来整体体系化的梳理下流程。
@SpringBootApplication
public class SpringBootApp {
public static void main(String[] args) {
// test
SpringApplication.run(SpringBootApp.class);
}
}
实际调用的是如下,也就是run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
// 调用重载的run方法,将传递的Class对象封装为了一个数组
return run(new Class<?>[] {
primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 创建了一个SpringApplication对象,并调用其run方法
// 1.先看下构造方法中的逻辑
// 2.然后再看run方法的逻辑
return new SpringApplication(primarySources).run(args);
}
基本可以分为两块,一个是构造方法,一个是run。
SpringBootApplication 构造方法
构造方法中,其实主要完成的工作,设置主启动类 primarySources,判断当前应用类型 servlet类型。通过公共方法,getSpringFactoriesInstances
进行获取目标类。然后设置到对应的初始化器以及监听器对象中。
然后通过堆栈信息获取主启动类
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 传递的resourceLoader为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 记录主方法的配置类名称 用set进行去重复
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 记录当前项目的类型 servlet类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化
// 并将加载的数据存储在了 initializers 成员变量中。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 反推main方法所在的Class对象 并记录在了mainApplicationClass对象中
this.mainApplicationClass = deduceMainApplicationClass();
}
其他的比较简单,主要分析下getSpringFactoriesInstances()方法
getSpringFactoriesInstances
整体流程,其实就是根据入参,从spring.factorties中 根据key获取对应的权限定类集合。
getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 根据入参类型 返回一个集合对象
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 获取当前上下文类加载器 默认是app类加载
ClassLoader classLoader = getClassLoader();
// 获取到的扩展类名存入set集合中防止重复
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 创建扩展点实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames
通过调用loadSpringFactories 从META-INF/spring.factories处读取相应配置文件,key是对应的 factoryTypeName value是多个类名。
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
// 根据Class获取名称
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
// 先查询缓存是否有 第一次进来是空
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {