当前位置: 首页 > article >正文

SpringBoot启动过程有哪些步骤(源码详细分析)

  1. 构造SpringApplication对象

我们从这里开始源码的解读

通过run方法会生成一个 SpringApplication对象 

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

我们进入springApplication方法里面,接着往下看,这个对象在构造的过程中做了哪些事情?

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
//表示传入的配置类
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//1.推测web应用类型(NONE,PEACTIVE,SERVLET)
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
//2.从spring.factories中获取BootstrapRegistryInitializer对象
		this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//3.从spring.factories中获取ApplicationContextInitializer对象
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4.从spring.factories中获取ApplicationListener对象 监听事件 
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//5.推测出Main类(main()方法所在的类)
		this.mainApplicationClass = deduceMainApplicationClass();
	}

	private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
		ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
		getSpringFactoriesInstances(Bootstrapper.class).stream()
				.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
				.forEach(initializers::add);
		initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		return initializers;
	}
  1. 推断应用类型:this.webApplicationType = WebApplicationType.deduceFromClasspath()

    • 通过类路径判断应用类型:

      • SERVLET:存在 Servlet API 和 DispatcherServlet(传统 Spring MVC)。

      • REACTIVE:存在 Spring WebFlux 的 DispatcherHandler

      • NONE:非 Web 应用。

  2. 加载引导注册初始化器:this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories()

    • 从 META-INF/spring.factories 加载 BootstrapRegistryInitializer 实现类。

    • 用于在引导阶段(如配置中心加载)注册自定义组件

  3. 设置初始化器:setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))

    • 通过 SpringFactoriesLoader 加载所有 ApplicationContextInitializer 实现类并实例化。

    • 这些初始化器会在 ApplicationContext 刷新前执行(如修改环境变量、注册 Bean)。

  4. 设置监听器:setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))

    • 加载所有 ApplicationListener 实现类并实例化。

    • 这些监听器用于响应应用事件(如上下文启动、失败等)。

  5. 推断主应用类:this.mainApplicationClass = deduceMainApplicationClass()

    • 通过分析调用栈找到包含 main 方法的类(即启动类)。

    • 用于日志输出或某些需要主类的场景。

 

以上是构建SpringApplication所需要完成的一些事情

下面构建完SpringApplication之后开始调用run方法,在这个过程中,又会做哪些事情呢,咱们接着往下看

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
//1.创建引导启动器,类似一个SpplicationContext,可以往里面添加一些对象,后续过程中(刷新)
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
//2.从spring.factories中获取SpringApplicationRunListeners对象
//默认会拿到一个EventPoblishingRunListener,它会启动过程的各个阶段发布对应的Application
		SpringApplicationRunListeners listeners = getRunListeners(args);
3.发布ApplicationStartingEvent
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
//4.将run()的参数封装为DefaultApplicationArguments对象
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//5.准备Environment
//将包括操作系统,JVM,ServletContext,properties,yaml,Ncos等等配置放入这个对象,是典型的key,value格式
//会发布一个ConfigurableEnvironmentPreParedEvent事件,表示环境已经准备好了,
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//默认spring.beaninfo.ignore=true,表示不需要jkd缓存beanInfo信息,Spring自己会缓存
			configureIgnoreBeanInfo(environment);
//打印Banner图片
			Banner printedBanner = printBanner(environment);
//6.根据类型创建Spring容器
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
//预处理Spring容器:
//7.利用SpringApplicationContextInitaializer初始化Spring容器
//8.发布SpringApplicationContextInitaializerEvent
//9.关闭DefaultBootstrapContext
//10.注册primarySources类,就是run方法存入进来的配置类
//11.发布ApplicationPreparedEvent事件,表示Spring容器已经准备好了
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//12.启动Spring容器,会解析配置类,扫描,启动WebServer,比如tomcat
			refreshContext(context);
//空方法,可以重新这个方法,完成自己的一些扩展
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
13.发布ApplicationStartedEvent,表示Spring容器已经启动
			listeners.started(context);
//14.从Spring容器中获取ApplicationRunner和ConmmandLinneRunner,并执行其run方法
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
//15.如果出现失败,会发布ApplicationFailedRvent事件,
			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. 启动计时与监控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
  • 作用:使用 StopWatch 记录应用启动耗时,用于后续日志输出。


2. 初始化引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  • 作用:创建 BootstrapContext,用于在应用启动的早期阶段(如配置中心加载)注册组件。

  • 底层机制:通过 BootstrapRegistryInitializer 实现自定义初始化逻辑(如加载外部配置)。


3. 配置 Headless 模式
configureHeadlessProperty();
  • 作用:强制设置 java.awt.headless=true,即使服务器没有图形界面或显示设备,也能正常运行。

  • 适用场景:处理图像生成、字体计算等操作(如 PDF 导出)。


4. 获取并触发启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
  • getRunListeners:从 META-INF/spring.factories 加载所有 SpringApplicationRunListener 实现类(如 EventPublishingRunListener)。

  • listeners.starting():触发 ApplicationStartingEvent 事件,通知监听器应用开始启动。


5. 准备应用环境
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  • ApplicationArguments:封装命令行参数(--key=value 格式),提供便捷的访问接口。

  • prepareEnvironment

    • 创建 ConfigurableEnvironment(如 StandardServletEnvironment)。

    • 加载配置文件(application.properties/application.yml)。

    • 触发 ApplicationEnvironmentPreparedEvent 事件,允许监听器修改环境配置(如 ConfigFileApplicationListener 加载配置文件)。


6. 忽略 BeanInfo 类
configureIgnoreBeanInfo(environment);
  • 作用:跳过对 BeanInfo 类的扫描,避免某些 JDK 类的元数据解析问题(如 java.beans.Introspector)。


7. 打印 Banner
Banner printedBanner = printBanner(environment);
  • 作用:根据配置输出启动 Banner(默认或自定义),可通过 spring.banner.location 指定 Banner 文件。


8. 创建应用上下文
context = createApplicationContext();
  • 根据应用类型(Servlet/Reactive/None)创建对应的 ConfigurableApplicationContext

    • ServletAnnotationConfigServletWebServerApplicationContext

    • ReactiveAnnotationConfigReactiveWebServerApplicationContext

    • NoneAnnotationConfigApplicationContext


9. 准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  • 关键操作

    1. 将 Environment 绑定到上下文。

    2. 执行 ApplicationContextInitializer 初始化器(如设置上下文 ID、注册 Bean)。

    3. 触发 ApplicationContextInitializedEvent 事件。

    4. 注册主配置类(primarySources)和命令行参数 Bean。

    5. 加载所有 BeanDefinitionLoader(如主类、XML 配置等)。


10. 刷新上下文(核心步骤)
refreshContext(context);
  • 作用:调用 AbstractApplicationContext.refresh(),完成 Spring 容器的初始化。

  • 关键子流程

    1. 准备 BeanFactory:注册必要的 Bean(如 environmentapplicationArguments)。

    2. 执行 BeanFactoryPostProcessor:处理配置类的解析(如 @Configuration)。

    3. 注册 BeanPostProcessor:干预 Bean 的创建过程(如 AOP 代理)。

    4. 初始化消息源、事件广播器

    5. 创建并初始化所有单例 Bean

    6. 启动 Web 服务器(如 Tomcat、Netty)。


11. 启动后回调
afterRefresh(context, applicationArguments);
listeners.started(context);
callRunners(context, applicationArguments);
  • afterRefresh:空方法,留给子类扩展。

  • listeners.started():触发 ApplicationStartedEvent,通知监听器应用已启动。

  • callRunners:执行所有 ApplicationRunner 和 CommandLineRunner 的 run() 方法,用于启动后执行自定义逻辑(如数据初始化)。


12. 完成启动
stopWatch.stop();
new StartupInfoLogger(...).logStarted(...);
listeners.ready(context);
  • 记录启动耗时:输出到日志。

  • 触发 ApplicationReadyEvent:通知应用已完全就绪(与 ApplicationStartedEvent 的区别在于,此时所有 Bean 已就绪)。


13. 异常处理
catch (Throwable ex) {
    handleRunFailure(context, ex, listeners);
    throw new IllegalStateException(ex);
}
  • handleRunFailure

    • 触发 ApplicationFailedEvent 事件。

    • 关闭应用上下文(如果已创建)。

    • 输出错误日志。

总结一下 SpringBoot启动过程步骤大致是:

构造SpringApplication对象->调用run方法(准备Environment-打印Banner->创建Spring容器->预处理Spring容器->刷新Spring容器


http://www.kler.cn/a/588936.html

相关文章:

  • 【大模型科普】大模型:人工智能的前沿(一文读懂大模型)
  • 图像处理篇---图像预处理
  • Java EE(11)——文件I(input)/O(output)
  • 新矩阵(信息学奥赛一本通-2041)
  • 算法练习(链表)
  • nodejs怎么引用别的项目里的node_modules
  • Mac 使用 Crossover 加载 Windows Steam 游戏库,实现 Windows/Mac 共享移动硬盘
  • 大数据技术
  • Docker 仓库相关操作命令大全及示例
  • Flask中使用WTForms处理表单验证
  • 配置blender的python环境
  • Qt 控件概述 QPushButton 与 QRadioButton
  • yarn安装及配置,cmd可以查看yarn版本号但是vscode无法查看且运行问题
  • 【LangChain接入阿里云百炼deepseek】
  • 《Python实战进阶》No21:数据存储:Redis 与 MongoDB 的使用场景
  • UML和MOF在MDA中的作用是什么?
  • Python文字识别OCR
  • Web开发-PHP应用鉴别修复AI算法流量检测PHP.INI通用过滤内置函数
  • Redis系列:深入理解缓存穿透、缓存击穿、缓存雪崩及其解决方案
  • STM32外部中断