Spring Boot 深度解析:从 0 到 1 探索启动之谜

引言

在日常开发中,我们经常使用 Spring Boot 来快速构建 Web 应用,但你是否深入思考过它的启动流程是如何工作的?当你在 main 方法中调用 SpringApplication.run() 时,Spring Boot 究竟经历了哪些关键步骤,最终成功启动了应用?

本篇文章将深入 Spring Boot 源码,剖析其启动流程,帮助你理解它的内部原理,让你在排查问题、优化启动速度时更加得心应手。

1. 启动入口

Spring Boot 应用通常以 SpringApplication.run() 作为入口:

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

该方法会初始化 SpringApplication 并调用 run() 方法启动 Spring Boot 应用。


2. SpringApplication.run() 启动流程

public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this);
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        listeners.started(context, timeTakenToStartup);
        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;
}

Spring Boot 的启动过程可以拆解为以下阶段:


1. 创建 SpringApplication 对象

public SpringApplication(Class<?>... primarySources) {
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
  • 通过 SpringFactoriesLoader 加载 ApplicationContextInitializerApplicationListener
  • 确定 WebApplicationType

2. 监听器通知 starting 事件

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this);

Spring Boot 触发 starting 事件,通知监听器应用正在启动。


3. 准备 Environment (环境变量)

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  • 加载 application.propertiesapplication.yml
  • 通知监听器 environmentPrepared 事件

4. 打印 Spring Boot Banner

Banner printedBanner = printBanner(environment);
  • 可通过 spring.banner.location 自定义 Banner。

5. 创建 ApplicationContext

context = createApplicationContext();
  • Web 应用创建 AnnotationConfigServletWebServerApplicationContext
  • 普通应用创建 AnnotationConfigApplicationContext

6. 准备 Spring 容器

prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  • 调用 ApplicationContextInitializer
  • 通知监听器 contextPrepared

7. 加载 Bean 定义

load(context, sources.toArray(new Object[0]));
  • 通过 AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner 扫描 Bean

8. 刷新 ApplicationContext

refreshContext(context);

最终调用 AbstractApplicationContext.refresh(),执行 BeanFactory 初始化流程。


9. 触发 started 事件

listeners.started(context, timeTakenToStartup);

并执行 ApplicationRunnerCommandLineRunner

callRunners(context, applicationArguments);

10. 通知 running 事件

listeners.running(context);

至此,Spring Boot 启动完成!


总结:Spring Boot 启动核心流程

  1. 创建 SpringApplication,加载监听器、环境类型。
  2. 触发 starting 事件,通知监听器应用正在启动。
  3. 准备 Environment,解析 application.properties 配置文件。
  4. 打印 Banner
  5. 创建 ApplicationContext 并注册环境。
  6. 调用 ApplicationContextInitializer 进行上下文初始化
  7. 加载 Bean,注册 BeanDefinition
  8. 刷新 ApplicationContext,完成 Bean 实例化、依赖注入。
  9. 触发 started 事件,执行 ApplicationRunnerCommandLineRunner
  10. 通知 running 事件,Spring Boot 启动完成。

整个启动流程以 SpringApplication.run() 作为起点,结合监听器、环境、应用上下文、BeanFactory 等组件,实现了 Spring Boot 的自动化启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值