Skip to content
清晨的一缕阳光
返回

Spring Boot 启动流程与生命周期

前言

理解 Spring Boot 的启动流程和生命周期,对于掌握 Spring Boot 核心原理、解决启动问题、进行扩展开发都至关重要。本文将深入剖析 Spring Boot 的启动过程。

SpringApplication 核心类

SpringApplication 是 Spring Boot 启动的核心类:

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

run 方法是静态方法,实际创建了 SpringApplication 实例:

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

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

启动流程详解

1. SpringApplication 构造

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

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 推断应用类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 加载 ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 加载 ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 推断主应用类
    this.mainApplicationClass = deduceMainApplicationClass();
}

2. run 方法执行

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    ConfigurableApplicationContext context = null;
    SpringApplicationRunException exception = null;
    
    // 1. 获取监听器
    Set<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(
        SpringApplicationRunListener.class, 
        new Class[] { SpringApplication.class, String[].class }, 
        this, args
    );
    
    // 2. 准备环境
    ConfigurableEnvironment environment = prepareEnvironment(listeners, args);
    
    // 3. 准备上下文
    prepareContext(context, environment, listeners, args);
    
    // 4. 刷新上下文
    refreshContext(context);
    
    // 5. 刷新后处理
    afterRefresh(context, applicationArguments);
    
    // 6. 发布启动完成事件
    listeners.started(context);
    
    // 7. 调用 Runner
    callRunners(context, applicationArguments);
    
    return context;
}

启动流程七步曲

Step 1: 获取监听器

加载 SpringApplicationRunListener,用于监听启动过程:

Set<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(
    SpringApplicationRunListener.class,
    new Class[] { SpringApplication.class, String[].class },
    this, args
);

主要监听器:

Step 2: 准备环境

创建并配置 Environment:

private ConfigurableEnvironment prepareEnvironment(
    SpringApplicationRunListeners listeners, 
    ApplicationArguments applicationArguments
) {
    // 创建 Environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置 PropertySources
    configurePropertySources(environment, applicationArguments);
    // 绑定环境到 Bean
    bindToSpringApplication(environment);
    // 发布环境准备事件
    listeners.environmentPrepared(environment);
    return environment;
}

Environment 包含:

Step 3: 准备上下文

创建 ApplicationContext 并准备:

private void prepareContext(
    ConfigurableApplicationContext context,
    ConfigurableEnvironment environment,
    SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments
) {
    // 设置环境
    context.setEnvironment(environment);
    // 后处理上下文
    postProcessApplicationContext(context);
    // 应用初始化器
    applyInitializers(context);
    // 发布上下文准备事件
    listeners.contextPrepared(context);
    // 加载主配置类
    load(context, sources.toArray(new Class[0]));
    // 发布上下文加载事件
    listeners.contextLoaded(context);
}

Step 4: 刷新上下文

核心步骤,刷新 ApplicationContext:

private void refreshContext(ConfigurableApplicationContext context) {
    context.refresh();
    // 注册关闭钩子
    context.registerShutdownHook();
}

context.refresh() 是 Spring 容器刷新的核心方法,执行以下操作:

  1. prepareRefresh() - 准备刷新
  2. obtainFreshBeanFactory() - 获取 BeanFactory
  3. prepareBeanFactory() - 准备 BeanFactory
  4. postProcessBeanFactory() - 后处理 BeanFactory
  5. invokeBeanFactoryPostProcessors() - 调用 BeanFactory 后处理器
  6. registerBeanPostProcessors() - 注册 Bean 后处理器
  7. initMessageSource() - 初始化消息源
  8. initApplicationEventMulticaster() - 初始化事件广播器
  9. onRefresh() - 子类重写刷新
  10. registerListeners() - 注册监听器
  11. finishBeanFactoryInitialization() - 完成 BeanFactory 初始化
  12. finishRefresh() - 完成刷新

Step 5: 刷新后处理

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    // 空方法,子类可以重写
}

Step 6: 发布启动完成事件

listeners.started(context);

发布 ApplicationStartedEvent 事件。

Step 7: 调用 Runner

执行 CommandLineRunner 和 ApplicationRunner:

private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {
    // 调用 ApplicationRunner
    context.getBeansOfType(ApplicationRunner.class)
        .values()
        .forEach(runner -> runner.run(args));
    
    // 调用 CommandLineRunner
    context.getBeansOfType(CommandLineRunner.class)
        .values()
        .forEach(runner -> runner.run(args));
}

生命周期事件

Spring Boot 启动过程发布以下事件:

1. ApplicationStartingEvent

最早的事件,在启动时立即发布:

@Component
public class StartingListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent event) {
        System.out.println("应用启动中...");
    }
}

2. ApplicationEnvironmentPreparedEvent

环境准备完成后:

@Component
public class EnvironmentListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment env = event.getEnvironment();
        System.out.println("环境准备完成:" + env.getProperty("spring.application.name"));
    }
}

3. ApplicationContextPreparedEvent

上下文准备完成后:

@Component
public class ContextPreparedListener implements ApplicationListener<ApplicationContextPreparedEvent> {
    @Override
    public void onApplicationEvent(ApplicationContextPreparedEvent event) {
        System.out.println("上下文准备完成");
    }
}

4. ApplicationStartedEvent

容器刷新完成后:

@Component
public class StartedListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("应用已启动");
    }
}

5. ApplicationReadyEvent

应用完全就绪,可以处理请求:

@Component
public class ReadyListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("应用已就绪");
    }
}

6. ApplicationFailedEvent

启动失败时:

@Component
public class FailedListener implements ApplicationListener<ApplicationFailedEvent> {
    @Override
    public void onApplicationEvent(ApplicationFailedEvent event) {
        System.err.println("启动失败:" + event.getException().getMessage());
    }
}

自定义启动流程

1. 使用 SpringApplicationRunListener

public class CustomRunListener implements SpringApplicationRunListener {
    
    public CustomRunListener(SpringApplication application, String[] args) {
        // 构造
    }
    
    @Override
    public void starting() {
        System.out.println("自定义:启动中");
    }
    
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        System.out.println("自定义:环境准备完成");
    }
    
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("自定义:上下文准备完成");
    }
    
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("自定义:上下文加载完成");
    }
    
    @Override
    public void started(ConfigurableApplicationContext context) {
        System.out.println("自定义:启动完成");
    }
    
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("自定义:就绪,耗时:" + timeTaken);
    }
    
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.err.println("自定义:启动失败");
    }
}

注册:

# META-INF/spring/org.springframework.boot.SpringApplicationRunListener.imports
com.example.demo.listener.CustomRunListener

2. 使用 ApplicationListener

@Component
public class CustomApplicationListener implements ApplicationListener<ApplicationEvent> {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            System.out.println("应用就绪,可以开始处理请求");
        }
    }
}

3. 使用 CommandLineRunner

@Component
public class StartupRunner implements CommandLineRunner {
    
    private final Environment environment;
    
    public StartupRunner(Environment environment) {
        this.environment = environment;
    }
    
    @Override
    public void run(String... args) {
        String port = environment.getProperty("local.server.port");
        System.out.println("应用启动完成,端口:" + port);
    }
}

启动时间优化

1. 分析启动时间

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.addListeners(event -> {
            if (event instanceof ApplicationReadyEvent) {
                ApplicationReadyEvent readyEvent = (ApplicationReadyEvent) event;
                System.out.println("启动耗时:" + readyEvent.getTimeTaken());
            }
        });
        app.run(args);
    }
}

2. 优化建议

总结

Spring Boot 启动流程:

  1. 获取监听器 - SpringApplicationRunListener
  2. 准备环境 - Environment、PropertySources
  3. 准备上下文 - ApplicationContext、Initializer
  4. 刷新上下文 - 核心步骤,创建 Bean
  5. 刷新后处理 - 可扩展点
  6. 发布启动事件 - ApplicationStartedEvent
  7. 调用 Runner - CommandLineRunner、ApplicationRunner

生命周期事件:

理解启动流程和生命周期,能帮助你更好地掌握 Spring Boot 核心原理。


分享这篇文章到:

上一篇文章
Hertz 高性能框架
下一篇文章
Sentinel 熔断降级