SpringBoot启动流程

这篇具有很好参考价值的文章主要介绍了SpringBoot启动流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

SpringBoot的启动都需要如下的启动类

@SpringBootApplication

public class SpringBootDemoApplication {

	public static void main(String[] args) {

		SpringApplication.run(SpringBootDemo3Application.class, args);

	}

}

分析启动类, 可以看出核心是:

  • 注解@SpringBootApplication
  • 方法SpringApplication.run(SpringBootDemoApplication.class, args)
    其中@SpringBootApplication之前已经了解过,如果想要了解可以查看SpringBoot自动装配原理及分析

一、方法SpringApplication.run(SpringBootDemoApplication.class, args)

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {

	return run(new Class<?>[] { primarySource }, args);

}

 

//继续点进下一层run方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {

	return new SpringApplication(primarySources).run(args);

}
  • 首先new了一个SpringApplication对象

  • 然后调用SpringApplication对象的run方法

二、实例化SpringApplication对象

调用SpringApplication的1个参数的构造函数,将启动类信息传入

public SpringApplication(Class<?>... primarySources) {
   this(null, primarySources);
}

SpringBoot启动流程,Spring,spring boot,java,后端

继续调用2个参数的构造方法,传入2个参数

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
    //断言有主配置类, 否则抛出异常
	Assert.notNull(primarySources, "PrimarySources must not be null");
    //保存主配置类信息
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //根据加载的处理器确定web应用的类型
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //获取所有的初始化器, 从spring.factories寻找
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //获取所有的应用监听器, 从spring.factories寻找
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	//推断main方法所在类
	this.mainApplicationClass = deduceMainApplicationClass();
}
  • 当前web应用类型

SpringBoot启动流程,Spring,spring boot,java,后端

  • 所有的初始化器

SpringBoot启动流程,Spring,spring boot,java,后端

  • 所有的应用监听器

SpringBoot启动流程,Spring,spring boot,java,后端

  • 在项目依赖所有的spring.factories文件中可以找到以上初始化器和监听器
#路径springframework\boot\spring-boot\2.3.4.RELEASE\spring-boot-2.3.4.RELEASE.jar!\META-INF\spring.factories
 
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
 
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
 
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
 
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
 
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
 
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
 
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer
 
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

源码解析
Springboot启动时,第一件重要事件就是构造SpringApplication对象,并主要完成如下事情。

  • 设置源。实际就是设置Spring容器启动时依赖的初始配置类,也就是Springboot中的启动类;
  • 设置WEB应用程序类型。例如可以是SERVLET,REACTIVE等;
  • 加载并设置Bootstrapper,ApplicationContextInitializer和ApplicationListener;
  • 设置应用程序主类的Class对象
    然后调用run(),具体步骤如下:

三、调用SpringApplication对象的run方法

将main方法中的args参数传入, 分析源码

public ConfigurableApplicationContext run(String... args) {
	// 秒表,用于记录启动时间;记录每个任务的时间,最后会输出每个任务的总费时
	StopWatch stopWatch = new StopWatch();
    //记录启动时间
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    //让当前应用进入headless模式(自力更生模式)。java.awt.headless
	configureHeadlessProperty();
    //获取所有的运行监听器(这个监听器和普通的Spring监听器不同,它只用于Spring容器的启动过程中)
    //默认会拿到一个EventPublishiingRunListener,它会在启动过程中的各个阶段发布对应的ApplicationEvent事件
	SpringApplicationRunListeners listeners = getRunListeners(args);
    //遍历 SpringApplicationRunListener 调用 starting 方法;相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting
	listeners.starting();
	try {
    	//保存命令行参数(args),将启动参数args封装为ApplicationArguments对象
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //准备环境, 返回或者创建基础环境信息对象 : StandardServletEnvironment
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        //根据环境配置需要忽略的bean信息
		configureIgnoreBeanInfo(environment);
       	//打印banner
        Banner printedBanner = printBanner(environment);
        //创建IOC容器(createApplicationContext())
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
			new Class[] { ConfigurableApplicationContext.class }, context);
        //准备IOC容器的基本信息
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //刷新IOC容器。refreshContext --->  创建容器中的所有组件(Spring注解)
        refreshContext(context);
        //容器刷新完成后 ---> 这是一个空方法,(目前无内容, 预留)
        afterRefresh(context, applicationArguments);
        //停止运行监听器停止运行, 记录容器启动完成花费的时间
        stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
        //所有监听器调用 listeners.started(context); 通知所有的监听器容器已创建完成
		listeners.started(context);
        //调用所有runners, 遍历执行runner的run方法
		callRunners(context, applicationArguments);
	}catch (Throwable ex) {
	//IOC容器创建失败,监听器会发布一个创建失败的事件
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}
 
	try {
    	//通知所有的监听器, 项目进入运行状态
		listeners.running(context);
	}catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

源码解析
1、StopWatch保存一些信息,应用名字,当前启动时间

2、创建引导上下文(context)

2.1:获取到所有之前创建的bootstrapers,挨个执行initialize方法,来完成对引导启动器上下文环境设置。(即引导启动的容器,在创建IOC容器前需要用到的公共对象就放在该容器中)

3、让当前应用进入headless模式。(用于在缺失显示屏、鼠标、键盘时候的系统配置)

4、获取所有RunListener运行时监听器(为了方便所有Listener进行事件感知,项目在启动)

4.1.getSpringFactoriesInstances去所有依赖的Spring.factories找SpringApplicationRunListener

4.2遍历所有SpringApplicationRunListener,调用starting方法,监听所有项目运行的状态(通知所有感兴趣系统正在启动过程的代码,项目正在starting)

4.3保存命令行参数;

4.4准备环境prepareEnviroment

4.4.1返回创建基础环境信息。StandardServletEnviroment

4.4.2配置环境信息对象(properties等)

4.4.2.1 读取所有配置元的配置属性

4.4.3绑定环境信息

4.4.4监听器调用environmentPrepared;通知所有监听器,当前环境准备完成。

4.5创建IoC容器(createApplicationContext)

4.5.1根据项目类型(Servlet)创建容器

4.5.2当前会创建AnnotationConfigServletWebServerApplicationContext;

4.6准备ApplicationContext IOC容器基本信息 prepareContext方法

4.6.1 保存环境信息

4.6.2 IOC容器的后置处理流程

4.6.3 应用初始化;applyInitializers

4.6.3.1 遍历所有的ApplicationContxtInitializer,调用initialize,来对IOC容器进行初始化扩展

4.7.4 遍历所有的Listener调用ContextPrepared。EventPublishListener;通知所有的监听器ContextPrepared

4.7.5 所有监听器 调用contextLoaded,通知上下文IOC容器加载完成。

4.7刷新IOC容器refresh(核心源码)

4.7.1创建容器中的所有组件

4.8刷新容器后的工作(空方法,扩展点,模板方法)

4.8.1所有监听器调用started方法,当前项目启动了

4.9调用runner方法;callRunners()

4.9.1获取容器中的ApplicationRunner

4.9.2获取容器中CommandLineRunner

4.9.3合并所有runner,并且按照@order进行排序

4.9.4遍历所有的runner调用run方法。

4.10如果有异常会调用Listener的failed方法

4.11调用所有监听器running方法Listener.running方法

4.12running方法如果有异常,还是调用Listener的failed方法。

四、总结

启动流程

  1. 从main方法开始。首先运行静态的run方法,创建一个springApplication对象,再运行run方法,工厂初始化配置在构造函数中完成。

    构造函数中进行了初始化配置:通过类加载器,(loadFactories)读取classpath下所有的spring.factories配置文件,创建一些初始化配置对象;

    run方法:通知监听器应用程序启动开始,创建环境对象environment,用于读取环境配置,如application.yml.

  2. 创建应用程序上下文-createApplicationContext,创建bean工厂对象

  3. 刷新上下文(启动核心)refreshContxt(工厂对象配置、bean处理器配置、类的扫描、解析、bean定义、bean类信息缓存、服务器Tomcat创建、bean实例化、动态代理对象创建)。

    3.1 配置工厂对象,包括上下文类加载器,对象发布处理器,beanFactoryPostProcessor。

    3.2 注册并实例化bean工厂发布处理器,并且调用这些处理器,对包扫描(主要是class)文件。

    3.3 注册并实例化bean发布处理器beanPostProcessor。

    3.4 初始化一些与上下文有特别关系的bean对象(创建tomcat服务器)

    3.5 实例化所有bean工 程缓存的bean对象

    3.6 发布通知上下文刷新完成(启动tomcat)

  4. 通知监听者-启动程序完成

    启动中大部分对象都是beanFactory对象通过反射创建

相关知识点:
1.Spring监听器能帮助开发者监听web中特定的事件,比如比如 ServletContext, HttpSession, ServletRequest 的创建和销毁;变量的创建、销毁等等。
它采用了观察者模式,观察者模式的模型主要是由 观察者实体 和 主题实体 构成。
SpringBoot启动流程,Spring,spring boot,java,后端
而Spring的监听器模式则结合了Spring本身的特征,也就是容器化。在Spring中,监听器
实体全部放在ApplicationContext中,事件也是通过ApplicationContext来进行发布,具体模型如下:
SpringBoot启动流程,Spring,spring boot,java,后端我们不难看到,虽说是通过ApplicationContext发布的事件,但其并不是自己进行事件的发布,而是引入了一个处理器—— EventMulticaster,直译就是事件多播器,它负责在大量的监听器中,针对每一个要广播的事件,找到事件对应的监听器,然后调用该监听器的响应方法,图中就是调用了监听器1、3、6。
PS: 只有在某类事件第一次广播时,EventMulticaster才会去做遍历所有监听器的事,当它针对该类事件广播过一次后,就会把对应监听器保存起来了,最后会形成一个缓存Map,下一次就能直接找到这些监听器

final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);

Spring监听器中不仅采用了观察者模式,但其实它还用到了适配器模式,工厂模式等。
想要了解具体原理分析参考https://blog.csdn.net/u011709538/article/details/130833755文章来源地址https://www.toymoban.com/news/detail-824195.html

到了这里,关于SpringBoot启动流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 3.x 系列【51】启动流程 | 最后阶段

    有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-boot3 终于启动流程到了最后一个阶段,这里主要是打印启动完成日志、调用监听器、运行 Runners 等 。

    2024年02月15日
    浏览(33)
  • 还不懂 Spring Boot 启动流程的,看这一篇就够了!

    通常,我们只需为一个类添加@SpringBootApplication注解,然后再添加一个main方法,其内固定的写法为SpringApplication.run(Application.class, args)。由此,便可启动Spring Boot服务。 具体而言,Spring Boot的启动流程包括以下几个步骤: 载入 Spring Boot 应用的启动类 根据启动类所在的包路径扫

    2024年02月05日
    浏览(32)
  • Spring Boot 3.x 系列【49】启动流程 | 创建、准备应用上下文

    有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-boot3

    2024年02月14日
    浏览(28)
  • SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月12日
    浏览(56)
  • 微信小程序的授权登录-Java 后端 (Spring boot)

    微信开发文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 一个可以测试的微信小程序 此微信小程序的APPID和APPscret(至开发者后台获取) 从时序图我们可以了解到流程大致分为两步: 小程序端获取code后传给Java后台 Java后台获取code后向微信后台接口

    2024年02月09日
    浏览(38)
  • SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月11日
    浏览(50)
  • “从零开始学习Spring Boot:快速搭建Java后端开发环境“

    标题:从零开始学习Spring Boot:快速搭建Java后端开发环境 摘要:本文将介绍如何从零开始学习Spring Boot,并详细讲解如何快速搭建Java后端开发环境。通过本文的指导,您将能够快速搭建一个基于Spring Boot的Java后端开发环境并开始编写代码。 正文: 一、准备工作 在开始之前,

    2024年02月15日
    浏览(42)
  • 【JAVA面试】Spring容器的启动流程

    提示:文章先作为初版,等后续时间充足后,补充更深的内容 当启动Spring容器时,会按照以下步骤进行: 扫描并注册Bean定义 :Spring容器会扫描指定的包或目录,查找带有 特定注解(如@Component、@Service、@Repository等)的类。它会创建对应的BeanDefinition对象 ,包含了Bean的元数

    2024年02月03日
    浏览(29)
  • Spring Boot学习随笔-第一个SpringBoot项目快速启动(org.springframework.boot、@SpringBootApplication、application.yml)

    学习视频:【编程不良人】2021年SpringBoot最新最全教程 创建第一个Module 环境要求 jdk1.8+ maven3.2+ Spring Framework 5.x+ Tomcat 9.0+ IDEA 2021 自动保存刷新pom 在resources下添加application.yml文件后,即可启动springboot应用 由于tomcat内嵌在springboot里面了,所以我们在修改端口号等设置也在配置

    2024年02月05日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包