spring boot 启动卡住_SpringBoot的启动过程

SpringBoot的启动过程

今天我们通过调试的方式讲述一下SpringBoot的启动的过程,加深自己的理解。

一、运行环境介绍

我们的运行环境是web的运行环境。

JDK:1.8

SpringBoot:2.2.2.RELEASE

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>

<groupId>com.breakpointgroupId>
<artifactId>spring-boot-learnartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>




<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>

<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
dependencies>


<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>

<executable>trueexecutable>
configuration>
plugin>
plugins>
build>
project>

二、启动的过程

2.1 创建SpringApplication对象并且执行run方法。
//org.springframework.context.ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

根据上面的执行的方式,可以总结为Spring启动的时候,一共做了2件事情:

1)、新建SpringApplication对象

2)、执行这个对象的run方法。

那么接下来分别看一看这2个方法都给咱们做了哪些的操作?

2.2 新建SpringApplication对象

新建SpringApplication对象是SpringBoot执行的第一个步骤:

// org.springframework.boot.SpringApplication#SpringApplication()
//
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置资源的加载对象
this.resourceLoader = resourceLoader;
//判断primarySources是不是null
Assert.notNull(primarySources, "PrimarySources must not be null");
// 设置主要资源的对象
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 决定当前应用的类别
// 由于我们用的是web,所以当前的应用视为 WebApplicationType.SERVLET 是一个服务
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 从项目的META-INF/spring.factories文件里找到所有的ApplicationContextInitializer的组件,设置到this.initializers对象上
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 这个和上面的相似,将META-INF/spring.factories所有的ApplicationListener对象获取出来,设置到this.listeners这个对象上
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 决定哪一个类是祝启动类
/*
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
上面的方式用了一个抛出异常的方式来决定哪一个类的里面存在main方法。
*/
this.mainApplicationClass = deduceMainApplicationClass();
}

决定当前的应用是web还是

d4a9919e7a45754dc6c544af226c2be9.png

2.3 执行run方法

下面的代码就是执行所有的run的方法。

public ConfigurableApplicationContext run(String... args) {
// 创建一个监视器,监视整个项目的启动,执行的开始时间以及结束的时间
StopWatch stopWatch = new StopWatch();
// 开始监视
stopWatch.start();
// 生命ConfigurableApplicationContext对象,也就是IOC容器,后面有具体的创建的过程
ConfigurableApplicationContext context = null;
// 创建 exceptionReporters 、也就是异常报告对象,如果我们的应用在启动的过场中,出现了异常,这个时候,会报告相关的操作
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
// 设置 SYSTEM_PROPERTY_JAVA_AWT_HEADLESS 的信息
configureHeadlessProperty();
// 从 META-INF/spring.factories 获取到所有的SpringApplicationRunListener组件
SpringApplicationRunListeners listeners = getRunListeners(args);
// 这个listeners开始监听
listeners.starting();
try {
// 设置应用的启动参数 也就是main防范的args参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境并且配置环境设置以及绑定到bindToSpringApplication上
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 配置环境
configureIgnoreBeanInfo(environment);
// 打印Banner 也就是springboot的图标
Banner printedBanner = printBanner(environment);
// 创建IOC容器对象,创建的过程中,根据不同的类别创建不同的IOC容器对象
/*
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
*/
context = createApplicationContext();
// 获取到错误的报告
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境
// 1/IOC容器设置环境
// 2.执行ApplicationContext 的后置处理器
// 3.调用ApplicationContextInitializer 的initialize方法在refreshed之前
// 4. 家在bean的定义到IOC容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新IOC容器
// 实际上就是调用Spring启动的核心的过程,调用各种的后置处理器以及初始化我们的bean的组件,并且将他们加入到IOC的容器中。
// 这一步,也创建了enbedded的tomcat的对象,并且在我们的配置好的端口上启动了
refreshContext(context);
// 准备好IOC的容器后的操作
afterRefresh(context, applicationArguments);
// 停止应用的监控,实际上,我们的主要的应用已经启动完成啦
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// SpringApplicationRunListener 的组件开始监听,也就是调用arted(context);的方法
listeners.started(context);
// 调用所有的Runners
/*
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
根据上面的代码,可以知道 调用了所有的ApplicationRunner 以及 CommandLineRunner的组件,也就是最后的一次回调了。
*/
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 如果有异常,那么就会报告异常
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}

try {
// 运行listeners.running
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

三、后记

经过上面的调试,更加的清晰的认识了SpringBoot的启动过程,SpringBoot还有其他许多的东西,比如自动装配等等这些比较重要的知识。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值