Spring Boot启动流程及源码实现深度解析

Spring Boot启动流程及源码实现深度解析

一、启动流程概述

Spring Boot的启动流程围绕SpringApplication类展开,核心流程可分为以下几个阶段:

  1. 初始化阶段 :推断应用类型,加载ApplicationContextInitializerApplicationListener
  2. 环境准备:加载配置文件和命令行参数
  3. 上下文创建 :实例化ApplicationContext
  4. 上下文刷新 :执行refresh()方法完成Bean加载
  5. 后置处理 :执行CommandLineRunnerApplicationRunner

二、源码解析

1. 入口类

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

2. SpringApplication初始化

java 复制代码
// SpringApplication.java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return new SpringApplication(primarySource).run(args);
}

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

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

关键步骤解析

  • deduceFromClasspath()通过类路径判断应用类型(Servlet/Reactive/None)
  • META-INF/spring.factories加载初始化器和监听器

3. run()方法核心流程

java 复制代码
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    ConfigurableApplicationContext context = null;
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        
        // 创建应用上下文
        context = createApplicationContext();
        context.setEnvironment(environment);
        
        // 准备上下文
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        
        // 刷新上下文(核心)
        refreshContext(context);
        
        // 后置处理
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        
        // 发布启动完成事件
        listeners.started(context);
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    listeners.running(context);
    return context;
}

三、关键阶段详解

1. 环境准备(prepareEnvironment)

java 复制代码
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(environment); // 发布环境准备事件
    bindToSpringApplication(environment);
    return environment;
}
  • 加载application.properties/yml文件
  • 处理命令行参数--开头的参数
  • 触发ApplicationEnvironmentPreparedEvent事件

2. 上下文创建(createApplicationContext)

根据应用类型创建不同的上下文:

java 复制代码
protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.create(this.webApplicationType);
}

// 默认实现
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    try {
        switch (webApplicationType) {
            case SERVLET:
                return new AnnotationConfigServletWebServerApplicationContext();
            case REACTIVE:
                return new AnnotationConfigReactiveWebServerApplicationContext();
            default:
                return new AnnotationConfigApplicationContext();
        }
    } catch (Exception ex) {
        throw new IllegalStateException(...);
    }
};

3. 上下文刷新(refreshContext)

java 复制代码
private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        } catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}

protected void refresh(ApplicationContext applicationContext) {
    ((AbstractApplicationContext) applicationContext).refresh();
}

最终调用AbstractApplicationContext.refresh(),这是Spring容器的核心方法:

java 复制代码
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        // ... [省略其他步骤]
        finishRefresh(); // 触发ContextRefreshedEvent
    }
}

四、关键扩展点

1. ApplicationContextInitializer

java 复制代码
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C applicationContext);
}
  • 执行时机:上下文准备阶段(prepareContext)
  • 配置方式:通过spring.factoriesSpringApplication.addInitializers()

2. ApplicationRunner/CommandLineRunner

java 复制代码
@Component
public class DemoRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        // 应用启动后执行
    }
}
  • 执行顺序:通过@Order注解控制
  • 执行时机:上下文刷新完成后

五、总结

Spring Boot的启动流程通过智能的自动配置和扩展机制,显著简化了Spring应用的初始化过程。理解其核心流程和关键扩展点,可以帮助开发者:

  1. 深入排查启动过程中的问题
  2. 实现自定义的初始化逻辑
  3. 优化应用启动性能
  4. 扩展框架的核心功能

建议结合源码调试工具,通过断点跟踪SpringApplication.run()的执行过程,可以更直观地理解各阶段的实现细节。


流程图文字描述

复制代码
main()
└─▶ SpringApplication.run()
    ├─▶ 初始化应用类型和扩展组件
    ├─▶ 准备环境(加载配置)
    ├─▶ 创建ApplicationContext
    ├─▶ 准备上下文(Bean定义加载)
    ├─▶ 刷新上下文(Bean初始化)
    ├─▶ 执行Runner接口
    └─▶ 完成启动

通过以上分析,读者可以系统地掌握Spring Boot的启动机制及其实现原理。实际开发中可结合具体需求,合理使用扩展点进行定制化开发。

相关推荐
渣哥3 分钟前
有一天,我和 CopyOnWriteArrayList 杯“线程安全”的咖啡
java
叽哥10 分钟前
Kotlin学习第 3 课:Kotlin 流程控制:掌握逻辑分支与循环的艺术
android·java·kotlin
杨杨杨大侠11 分钟前
第5章:实现Spring Boot集成
java·github·eventbus
华仔啊13 分钟前
工作5年没碰过分布式锁,是我太菜还是公司太稳?网友:太真实了!
java·后端
尚久龙17 分钟前
安卓学习 之 图片控件和图片按钮
android·java·学习·手机·android studio·安卓
摸鱼仙人~19 分钟前
深入理解 MyBatis-Plus 的 `BaseMapper`
java·开发语言·mybatis
杨杨杨大侠20 分钟前
第6章:高级特性与性能优化
java·github·eventbus
卿·静29 分钟前
Node.js对接即梦AI实现“千军万马”视频
前端·javascript·人工智能·后端·node.js
Dcs43 分钟前
代码评审还能更好!
java
刃神太酷啦1 小时前
C++ 异常处理机制:从基础到实践的全面解析----《Hello C++ Wrold!》(20)--(C/C++)
java·c语言·开发语言·c++·qt·算法·leetcode