SpringBoot 启动源码分析

SpringBoot 2.4.3

SpringBoot 启动源码分析

启动类run()方法跟进去有两步,一是初始化,二是SpringApplication.run()方法的执行

初始化
1.配置resourceLoader
2.判断当前应用程序的类型
3.获取初始化容器实例对象
4.找到当前应用程序的主类,开始执行
.
运行
1.获取并启动监听器
2.构造容器环境,初始化默认应用参数类。根据运行监听器和应用参数来准备Spring环境
3.第三步:创建容器(应用上下文)
4.
5.准备容器
6.刷新容器

main

@SpringBootApplication
public class TestApplication {
  public static void main(String[] args){SpringApplication.run(TestApplication.class, args);}
}

一 初始化

1.配置resourceLoader
2.判断当前应用程序的类型
3.获取初始化容器实例对象
4.找到当前应用程序的主类,开始执行

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
		//获取ApplicationContextInitializer,也是在这里开始首次加载spring.factories文件
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//获取监听器,这里是第二次加载spring.factories文件
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

1 配置resourceLoader

2 判断当前应用程序的类型

webApplicationType = Servlet

3 获取初始化容器实例对象

getSpringFactoriesInstances – loadFactoryNames 获取工厂实例
在这里插入图片描述

loadFactoryNames

loadSpringFactories
读取 key value 通过反射进行实例化
在这里插入图片描述

加载配置文件 spring.factories

其中 Application Listeners 监听器为9个。
还有1个是:org.springframework.boot.autoconfigure.BackgroundPreinitializer
这10个监听器会贯穿springBoot整个生命周期。
在这里插入图片描述

createSpringFactoriesInstances

创建对象实例 实例化7个对象
在这里插入图片描述

4 找到当前应用程序的主类,开始执行

deduceMainApplicationClass

继续后面的流程。进入run方法

二 Run

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();//时间监控
	stopWatch.start();
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;
	//java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
	configureHeadlessProperty();
	//获取spring.factories中的监听器变量,args为指定的参数数组,默认为当前类SpringApplication
	//第一步:获取并启动监听器
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting(bootstrapContext, this.mainApplicationClass);
	try {
	    //第二步:构造容器环境,初始化默认应用参数类,设置命令行参数
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		//根据运行监听器和应用参数来准备Spring环境
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		//设置需要忽略的bean
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);//打印banner
		//第三步:创建容器(应用上下文)
		context = createApplicationContext();
		context.setApplicationStartup(this.applicationStartup);
		//第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
		//第五步:准备容器
	    prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
	    //第六步:刷新容器
		refreshContext(context);
		//第七步:刷新容器后的扩展接口
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
		callRunners(context, applicationArguments);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		listeners.running(context);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

1 加载并启动监听器

获取11个监听器,加载到缓存,根据事件进行匹配
starting()

1.1 创建监听器对象

创建监听器对象SpringApplicationRunListener 从配置文件中读取到EventPublishingRunListener
在这里插入图片描述
Spring事件发布(监听)机制,回调机制,观察者模式
在这里插入图片描述

multicastEvent

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			invokeListener(listener, event);
		}
	}
}
11+1 EventPublishingRunListener、ApplicationStartingEvent

从配置文件中读取 EventPublishingRunListener
创建EventPublishingRunListener对象,并且创建出SimpleApplicationEventMultiCaster,将application的11个监听器给到当前对象,此时才能方面我们从中获取出符合监听事件的几个监听器。
将11个对象放到当前listeners中,向下开始
for循环
在这里插入图片描述

1.3 获取监听器的实例对象

在这里插入图片描述

EventPublishingRunListener

构造方法
在这里插入图片描述

addApplicationListener

这是一个内部类,用来保存所有的监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中
在这里插入图片描述
在这里插入图片描述

supportEvent

遍历11个监听器,从过滤器中匹配出当前事件,把可以监听ApplicationStartingEvent 事件拿出来,并启动。
在这里插入图片描述

4 ConfigurationApplicationContext 未实现

未实现

2 解析参数值,构造容器环境,初始化默认应用参数类

从命令行中解析参数值,设置命令行参数 --key=value 如 javar -D --server.port=8085 Test.jar,并进行匹配

//第二步:构造容器环境,初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//根据运行监听器和应用参数来准备Spring环境 创建和配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

DefaultApplicationArguments
Source
在这里插入图片描述
SimpleCommandLinePropertySource.java
在这里插入图片描述

SimpleCommandLineArgsParser

在这里插入图片描述

创建Servlet环境

prepareEnvironment()

getOrCreateEnvironment() = this.webApplicationType //创建Servlet 环境对象
attach()//加载一些环境属性值
4
5将
在这里插入图片描述

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
	// 1 构建一个标准的Servlet环境
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	//3 附加一些环境属性值
	ConfigurationPropertySources.attach(environment);
	//4 监听器启动时的环境准备工作
	listeners.environmentPrepared(bootstrapContext, environment);
	DefaultPropertiesPropertySource.moveToEnd(environment);
	configureAdditionalProfiles(environment);
	//5 将当前的环境绑定到Application中
	bindToSpringApplication(environment);
	//6 判断环境对象是否符合当前类型,不符合再进行转换
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	//7 增加其他属性
	ConfigurationPropertySources.attach(environment);
	return environment;
}

getOrCreateEnvironment

1

在这里插入图片描述
查看类图
在这里插入图片描述

StandarServletEnvironment.java(spring-web包)
引入 servlet中两个最基础的配置:servletContextInitParams、servletConfigInitParams
在这里插入图片描述

将服务设置到当前环境中去,同时也包含系统参数 systemEnvironment
在这里插入图片描述

在这里插入图片描述

添加参数转化器服务 ConversionService

添加参数转化器服务 ConversionService
设置环境变量
设置命令行参数,默认为null
getSharedInstance();//返回一个共享的Application的实例
在这里插入图片描述
在这里插入图片描述

configureProfiles(environment, args)

getActiveProfiles()
根据属性值spring.profiles.active 判断当前开发环境 dev环境、production环境
注:此时未加载application.yml文件
在这里插入图片描述
根据属性值spring.profiles.active,判断环境配置参数
![在这里插入图片描述](https://img-blog.csdnimg.cn/582f880f23fc4baab8c3306f84434cb4.pn
从11个监听器中找出7个集合
在这里插入图片描述

配置文件
在这里插入图片描述
在这里插入图片描述

loadPostProcessors

EnvironmentPostProcessor.class

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

最后通过for循环加入EnvironmentPostProcessor

addToEnvironment

RandomValuePropertySource 是配置文件中使用了${random}函数

RandomValuePropertySource.addToEnvironment()
在这里插入图片描述
在这里插入图片描述

postProcessEvnironment

SystemEnvironmentPropertySourceEnvironmentPostProcessor.postProcessEvnironment()
在这里插入图片描述

加载 ProperttySource Loaders

new Loader(environment, resourceLoader).load();

yml

YamlPropertySourceLoader.class
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值