森罗荡荡

森罗荡荡

  前面给大家介绍了SpringBoot启动的核心流程,本文开始给大家详细的来介绍SpringBoot启动中的具体实现的相关细节。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

springboot源码怎么看SpringBoot2.png

SpringApplication构造器

  首先我们来看下在SpringApplication的构造方法中是如何帮我们完成这4个核心操作的。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

 1    @SuppressWarnings({ "unchecked", "rawtypes" })
 2    public SpringApplication(ResourceLoader resourceLoader, Class<#>... primarySources) {
 3        // 传递的resourceLoader为null
 4        this.resourceLoader = resourceLoader;
 5        Assert.notNull(primarySources, "PrimarySources must not be null");
 6        // 记录主方法的配置类名称
 7        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
 8        // 记录当前项目的类型
 9        this.webApplicationType = WebApplicationType.deduceFromClasspath();
10        // 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化
11        // 并将加载的数据存储在了 initializers 成员变量中。
12        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
13        // 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
14        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
15        // 反推main方法所在的Class对象 并记录在了mainApplicationClass对象中
16        this.mainApplicationClass = deduceMainApplicationClass();
17    }

1.webApplicationType

  首先来看下webApplicationType是如何来推导出当前启动的项目的类型。通过代码可以看到是通过deduceFromClassPath()方法根据ClassPath来推导出来的。

1this.webApplicationType = WebApplicationType.deduceFromClasspath();

  跟踪进去看代码

SpringBoot源码分析之SpringApplication构造方法核心源码分析

在看整体的实现逻辑之前,我们先分别看两个内容,第一就是在上面的代码中使用到了相关的静态变量。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  这些静态变量其实就是一些绑定的Java类的全类路径。第二个就是 ClassUtils.isPresent()方法,该方法的逻辑也非常简单,就是通过反射的方式获取对应的类型的Class对象,如果存在返回true,否则返回false

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  所以到此推导的逻辑就非常清楚了

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

2.setInitializers

  然后我们再来看下如何实现加载初始化器的。

1// 加载配置在spring.factories文件中的ApplicationContextInitializer对应的类型并实例化
2        // 并将加载的数据存储在了 initializers 成员变量中。
3        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

  首先所有的初始化器都实现了
ApplicationContextInitializer接口,也就是根据这个类型来加载相关的实现类。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

 然后加载的关键方法是
getSpringFactoriesInstances()方法。该方法会加载 spring.factories文件中的key为
org.springframework.context.ApplicationContextInitializer 的值。

spring-boot项目下

1# Application Context Initializers
2org.springframework.context.ApplicationContextInitializer=
3org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
4org.springframework.boot.context.ContextIdApplicationContextInitializer,
5org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
6org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,
7org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

spring-boot-autoconfigure项目下

1# Initializers
2org.springframework.context.ApplicationContextInitializer=
3org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
4org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

具体的加载方法为 `getSpringFacotiesInstance()`方法,我们进入查看

  先进入
SpringFactoriesLoader.loadFactoryNames(type, classLoader)中具体查看加载文件的过程.

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  然后我们来看下 loadSpringFactories方法

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  通过Debug的方式查看会更清楚哦

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  通过 loadSpringFactories 方法我们看到把 spring.factories文件中的所有信息都加载到了内存中了,但是我们现在只需要加载
ApplicationContextInitializer类型的数据。这时我们再通过 getOrDefault()方法来查看。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  进入方法中查看

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  然后会根据反射获取对应的实例对象。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  好了到这其实我们就清楚了
getSpringFactoriesInstances方法的作用就是帮我们获取定义在 META-INF/spring.factories文件中的可以为
ApplicationContextInitializer 的值。并通过反射的方式获取实例对象。然后把实例的对象信息存储在了SpringApplication的 initializers属性中。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

3.setListeners

  清楚了 setInitializers()方法的作用后,再看 setListeners()方法就非常简单了,都是调用了
getSpringFactoriesInstances方法,只是传入的类型不同。也就是要获取的 META-INF/spring.factories文件中定义的不同信息罢了。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  即加载定义在 META-INF/spring.factories文件中声明的所有的监听器,并将获取后的监听器存储在了 SpringApplication的 listeners属性中。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  默认加载的监听器为:

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

4.mainApplicationClass

  最后我们来看下
duduceMainApplicaitonClass()方法是如何反推导出main方法所在的Class对象的。通过源码我们可以看到是通过 StackTrace来实现的。

1StackTrace:
2我们在学习函数调用时,都知道每个函数都拥有自己的栈空间。
3一个函数被调用时,就创建一个新的栈空间。那么通过函数的嵌套调用最后就形成了一个函数调用堆栈

  StackTrace其实就是记录了程序方法执行的链路。通过Debug方式可以更直观的来呈现。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  那么相关的调用链路我们都可以获取到,剩下的就只需要获取每链路判断执行的方法名称是否是 main就可以了。

SpringBoot源码分析之SpringApplication构造方法核心源码分析

image.png

  好了到此相关的4个核心步骤就给大家分析完了,希望对大家能有所帮助哦!