目录

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

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

  1. 构造SpringApplication对象

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

https://i-blog.csdnimg.cn/direct/5d924cbb14844c4ba5b0bf1b3ae5bf22.png

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

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

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

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 :执行所有 ApplicationRunnerCommandLineRunnerrun() 方法,用于启动后执行自定义逻辑(如数据初始化)。

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容器