SpringBoot启动过程学习记录
//主程序入口
public static void main(String[] args) {
SpringApplication.run(FirstSpringBootApplication.class, args);
}
//SpringBoot框架静态run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
//重载的run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
SpringBoot项目,启动的方式,默认是使用 SpringApplication.run(Class<?> primarySource, String… args) 方法来启动的,然后run方法呢,分为两部分,一部分是构建SpringApplication对象的过程,还有一部分是run。
1.构建过程
public static void main(String[] args) {
SpringApplication.run(FirstSpringBootApplication.class, args);
}
程序入口,首先把主程序的class,和运行参数args作为参数传到run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
程序进来后可以看到,我们传的FirstSpringBootApplication.class,args
然后他把我们的字节码对象封装成了一个数组对象,然后继续运行了另外一个run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
这是一个重载的run方法,在这里,就能看到我们的2部分了,一部分是new SpringApplication(primarySources)
一部分是run(args)
我们继续往下看new SpringApplication(primarySources)
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
这是一个构造方法,调用了另一个构造方法,继续往下看另一个构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader; //赋值给resourceLoader 前面传的是一个null值
Assert.notNull(primarySources, "PrimarySources must not be null"); //断言,判断primarySources
//使用primarySources创建了一个set集合赋值给primarySources
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
/**
*这一步,主要是判断SpringBoot是什么程序
*WebApplicationType是一个枚举类,deduceFromClasspath()方法,主要通过各种全限定类名,判断各种类的可加载情况
*这里就不做过多的分析了
*/
this.webApplicationType = WebApplicationType.deduceFromClasspath();
/**
*getSpringFactoriesInstances方法,是通过传递的字节码对象,获取类加载器,
*通过使用给定的类加载器从"META-INF/spring.factories"加载给定类型的工厂实现的完全限定类名。
*通过全限定类名,创建工厂实现的实例集合。
*/
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
getSpringFactoriesInstances详解
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//getClassLoader()方法获取传进来的字节码对象的类加载器,如果传的是null则获取默认的类加载器
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
请注意,**getClassLoader()**方法
public ClassLoader getClassLoader() {
//判断this.resourceLoader,这个属性,在上面this(null, primarySources);调用这个构造方法的时候,传了一个null参数
//public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//this.resourceLoader = resourceLoader; //赋值给resourceLoader 前面传的是一个null值
//所以,这里这个if是为false,所以我们获取到的是getDefaultClassLoader
//
if (this.resourceLoader != null) {
return this.resourceLoader.getClassLoader();
}
/**
*返回要使用的默认 ClassLoader:通常是线程上下文 ClassLoader; 加载 ClassUtils 类的 ClassLoader 将用作后备。
*/
return ClassUtils.getDefaultClassLoader();
}