知识储备:SpringBoot启动运行流程原理解析

SpringBoot项目通过SpringApplication.run()运行,分为两步

首先new了一个SpringApplication,之后再调用run()方法 ,下面我们就看看这两步

1.创建SpringApplication

通过debug进入到SpringApplication的创建中

知识储备:SpringBoot启动运行流程原理解析_第1张图片

首先判断当前项目是否是web项目,再在所有jar包的META-INF/spring.factories文件中查找ApplicationContextInitializer和ApplicationListener并保存,之后再通过所有配置类获得带有main方法的主运行类

知识储备:SpringBoot启动运行流程原理解析_第2张图片

获得的所有ApplicationContextInitializer类型

知识储备:SpringBoot启动运行流程原理解析_第3张图片

获得所有的ApplicationListener类型,到这里SpringApplication就创建完成

2.调用run()方法

通过debug进入其中

知识储备:SpringBoot启动运行流程原理解析_第4张图片

在这里首先通过spring.factories文件获得所有SpringApplicationRunListener,循环调用他们的starting方法

封装命令行参数

接下来就是准备环境,通过debug进入其中

知识储备:SpringBoot启动运行流程原理解析_第5张图片

发现,首先创建环境,在回调SpringApplicationRunListener的environmentPrepared()方法,表示环境准备完成

之后就创建ApplicationContext,进入其中

知识储备:SpringBoot启动运行流程原理解析_第6张图片

知识储备:SpringBoot启动运行流程原理解析_第7张图片

发现,通过判断创建不同容器,最后通过反射创建,因为我们这里是web环境,就会得到AnnotationConfigServletWebServerApplicationContext

接下来,准备上下文

进入其中

知识储备:SpringBoot启动运行流程原理解析_第8张图片

发现将之前创建的容器添加到其中,主要调用了applyInitializers(context);方法,这个方法时干啥的呢?进入其中

知识储备:SpringBoot启动运行流程原理解析_第9张图片

发现在循环所有的ApplicationContextInitializer,回调他们的initialize()方法,而这些ApplicationContextInitializer就是在SpringApplication创建时,在spring.factories文件中加载的ApplicationContextInitializer。所有的ApplicationContextInitializer的initialize()方法回调完毕,又回调SpringApplicationRunListeners的contextPrepared()方法

知识储备:SpringBoot启动运行流程原理解析_第10张图片

接下来

知识储备:SpringBoot启动运行流程原理解析_第11张图片

回调SpringApplicationRunListeners的contextLoaded()方法,至此prepareContext()方法就调用完毕,之后来到refreshContext(context);方法,刷新容器,就是IOC容器初始化的过程

IOC初始化调用refresh()方法(不熟悉IOC容器的初始化的可以看https://blog.csdn.net/qq_36625757/article/details/83856575这篇博客

知识储备:SpringBoot启动运行流程原理解析_第12张图片

refreshContext(context);执行完毕,IOC容器就创建完毕了,所有的bean就创建完毕,如果是web应用Tomcat或其他Servlet容器也创建完毕,之后就调用所有SpringApplicationRunListeners的started()方法

知识储备:SpringBoot启动运行流程原理解析_第13张图片

最后调用callRunners(context, applicationArguments);方法,进入其中

知识储备:SpringBoot启动运行流程原理解析_第14张图片

发现从容器中出的ApplicationRunner及CommandLineRunner,并先调用ApplicationRunner在调用CommandLineRunner,说明他们之间存在优先级,之后再调用所有SpringApplicationRunListeners的running()方法

最后SpringBoot启动完成,返回IOC容器

知识储备:SpringBoot启动运行流程原理解析_第15张图片

3.核心回调机制

1.配置在META-INF/spring.factories的ApplicationContextInitializer,SpringApplicationRunListener

2.通过容器获得的ApplicationRunner,CommandLineRunner,下面我们就看看这几个类

4.创建各个接口的实现,并配置

1.创建ApplicationContextInitializer实现

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

//需要配置在spring.factories文件中
public class HelloApplicationContextInitializer implements ApplicationContextInitializer {//监听ConfigurableApplicationContext

	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		System.out.println("HelloApplicationContextInitializer.initialize()方法运行啦!!!!!!!!!!!!!!!!!!!!");
	}

}

2.创建SpringApplicationRunListener的实现类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

//需要配置在spring.factories文件中
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {
	
	//必须要有这个构造器
	public HelloSpringApplicationRunListener(SpringApplication application, String[] args) {}

	//这边在spring刚拿到所有的SpringApplicationRunListener实现类后就直接调用了starting 通知各个SpringApplicationRunListener的实现类
	@Override
	public void starting() {
		System.out.println("HelloSpringApplicationRunListener.starting()调用啦!!!!!!!!!!!!");
	}

	//在准备好了ConfigurableEnvironment环境的时候通知各个实现类
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		Object osName = environment.getSystemProperties().get("os.name");//获得操作系统名称
		System.out.println("HelloSpringApplicationRunListener.environmentPrepared()调用啦!!!!!!!!!!!!"+osName);
	}

	//在spring 结束applyInitializers后进行通知
	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		System.out.println("HelloSpringApplicationRunListener.contextPrepared()调用啦!!!!!!!!!!!!");
	}

	//在加载完资源类(启动类)后触发
	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		System.out.println("HelloSpringApplicationRunListener.contextLoaded()调用啦!!!!!!!!!!!!");
	}

	//在所有的bean 都初始化后 进行触发
	@Override
	public void started(ConfigurableApplicationContext context) {
		System.out.println("HelloSpringApplicationRunListener.started()调用啦!!!!!!!!!!!!");

	}

	//在调用完所有的ApplicationRunner和CommandLineRunner实现类后调用
	@Override
	public void running(ConfigurableApplicationContext context) {
		System.out.println("HelloSpringApplicationRunListener.running()调用啦!!!!!!!!!!!!");
	}

	//应用程序发生故障时调用
	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		System.out.println("HelloSpringApplicationRunListener.failed()调用啦!!!!!!!!!!!!");
	}

}

3.创建ApplicationRunner的实现类

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component//加入到容器中
public class HelloApplicationRunner implements ApplicationRunner {

	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("HelloApplicationRunner.run()方法调用啦!!!!!!!!!!!!!!");
	}

}

4.创建CommandLineRunner的实现类

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component//加入到容器中
public class HelloCommandLineRunner implements CommandLineRunner {

	@Override
	public void run(String... args) throws Exception {
		System.out.println("HelloCommandLineRunner.run()方法调用啦!!!!!!!!!!!!!!!");
	}

}

5.配置ApplicationContextInitializer及SpringApplicationRunListener,在类路径下创建spring.factories文件,编辑为

org.springframework.context.ApplicationContextInitializer=\
com.peng.demo.listener.HelloApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=\
com.peng.demo.listener.HelloSpringApplicationRunListener

6.运行发现,在应用启动过程中回调了不同的方法,至于在啥时候回调的,前面流程分析中已有介绍

知识储备:SpringBoot启动运行流程原理解析_第16张图片

5.总结

查看了SpringBoot启动流程,最主要就是ApplicationContextInitializer,SpringApplicationRunListener,ApplicationRunner,CommandLineRunner四个接口实现类方法的回调,这四个接口的主要作用就是在SpringBoot 启动初始化的过程中可以通过四个接口实现类方法回调来让用户在启动的各个流程中可以加入自己的逻辑

你可能感兴趣的:(SpringBoot)