本文自己写的(头条也有这篇文章),若有问题,请指正。
大致流程如下:
1. 初始化SpringApplication,从META-INF下的spring.factories读取
ApplicationListener/ApplicationContextInitializer
2.运行SpringApplication的run方法
3.读取项目中环境变量、jvm配置信息、配置文件信息等
4.创建Spring容器对象(ApplicationContext)
5. 利用
ApplicationContextInitializer初始化Spring容器对象,读取启动类
6.调用spring的refresh加载IOC容器、自动配置类,并创建bean、servlet容器等信息
7.springboot会调用很多监听器
8.如果启动时发生异常,则发送ApplicationFailedEvent事件
下面对上述流程进行源码细化分析,首先调用SpringApplication.run启动springboot应用:
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@EnableTransactionManagement(proxyTargetClass = true)
@Import(MyDynamicDataSourceConfig.class)
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class, args);
}
}
进入run方法后,会进行SpringApplication进行启动,分两大步,第一步初始化SpringApplication,第二步调用run方法:
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
第一步初始化SpringApplication,new SpringApplication(primarySources)的流程如下(具体方法含义参考注释):
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 根据classpath下的类,推算当前web应用类型(REACTIVE/SERVLET/NONE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 获取BootstrapRegistryInitializer对象,从META-INF/spring.factories中读取key为BootstrapRegistryInitializer,并实例化出对象
// BootstrapRegistryInitializer的作用是可以初始化BootstrapRegistry
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//去spring.factories中去获取所有key:org.springframework.context.ApplicationContextInitializer为了初始化Spring容器ApplicationContext对象(可以利用
//ApplicationContextInitializer向Spring容器中添加ApplicationListener)
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//去spring.factories中去获取所有key: org.springframework.context.ApplicationListener,ApplicationListener是Spring中的监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推测main()方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
第二步调用run方法,初始化完SpringApplication开始运行run方法,源码如下:
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();//记录时间
//创建DefaultBootstrapContext对象,利用BootstrapRegistryInitializer初始化DefaultBootstrapContext对象
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 开启了Headless模式:
configureHeadlessProperty();
//获取SpringApplicationRunListeners, //SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口
//spring会利用这个类,发布一个ApplicationContextInitializedEvent事件,可以通过定义ApplicationListener来消费这个事件
SpringApplicationRunListeners listeners = getRunListeners(args);
// 发布ApplicationStartingEvent事件,在运行开始时发送
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 根据命令行参数 实例化一个ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 预初始化环境(见下面的源码分析): 读取环境变量(操作系统的环境变量/JVM的环境变量),读取配置文件信息(基于监听器,会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,
//默认会有一个EnvironmentPostProcessorApplicationListener来处理这个事件,当然也可以通过自定义ApplicationListener来处理这个事件,当ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,
//并添加到Environment中)
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);// 打印Banner
//据webApplicationType创建不同的Spring上下文容器(有三种)
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//预初始化spring上下文,见下面的源码分析
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新Spring容器,这一步中创建并初始化bean,创建并启动tomacat等(以tomcat为例,调到ServletWebServerApplicationContext的createWebServer()方法
//最后执行TomcatServletWebServerFactory的getWebServer方法)
refreshContext(context);
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
//发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件
listeners.started(context, timeTakenToStartup);
// 获取Spring容器中的ApplicationRunner/CommandLineRunner类型的Bean,并执行run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);//发布ApplicationFailedEvent事件
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
//发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);//发布ApplicationFailedEvent事件
throw new IllegalStateException(ex);
}
return context;
}
预初始化环境,创建Environment对象源码解析:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 根据webApplicationType 创建Environment 创建就会读取: java环境变量和系统环境变量
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 将命令行参数读取环境变量中
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 将@PropertieSource的配置信息 放在第一位,它的优先级是最低的
ConfigurationPropertySources.attach(environment);
// 发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件
listeners.environmentPrepared(bootstrapContext, environment);
// 将所有spring.main 开头的配置信息绑定到SpringApplication中
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);//更新PropertySources
return environment;
}
预初始化spring上下文源码解析: 文章来源:https://www.toymoban.com/news/detail-476081.html
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);// 拿到之前读取到所有ApplicationContextInitializer的组件, 循环调用initialize方法
listeners.contextPrepared(context);// 发布了ApplicationContextInitializedEvent
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取当前spring上下文beanFactory (负责创建bean)
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
//在SpringBoot 在这里设置了不允许覆盖, 当出现2个重名的bean 会抛出异常
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 设置当前spring容器是不是要将所有的bean设置为懒加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 读取主启动类 (因为后续要根据配置类解析配置的所有bean),将启动类作为配置类注册到Spring容器中
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);//读取完配置类后发送ApplicationPreparedEvent,默认利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件
}
文章来源地址https://www.toymoban.com/news/detail-476081.html
到了这里,关于springboot启动流程源码解析(带流程图)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!