13、SpringBoot启动过程

SpringBoot启动过程:加载配置,初始化环境,创建应用上下文,执行自动配置,扫描组件,初始化Bean,启动内嵌服务器,完成应用启动,最后运行CommandLineRunner或ApplicationRunner接口的实现类。


1、启动入口

SpringBoot应用的启动入口通常是main方法,调用SpringApplication.run()

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

2、SpringApplication初始化

SpringApplication的初始化过程:

java 复制代码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}

关键步骤:

  1. 推断应用类型(WEB/NONE)
  2. 加载META-INF/spring.factories中的ApplicationContextInitializerApplicationListener
  3. 推断主配置类

3、run()方法执行流程

run()方法是整个启动过程的核心:

java 复制代码
public ConfigurableApplicationContext run(String... args) {
    // 1. 创建并启动计时器
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    // 2. 准备环境
    ConfigurableApplicationContext context = null;
    ConfigurableEnvironment environment = prepareEnvironment(...);

    // 3. 打印Banner
    Banner printedBanner = printBanner(environment);

    // 4. 创建应用上下文
    context = createApplicationContext();

    // 5. 准备上下文
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);

    // 6. 刷新上下文(核心)
    refreshContext(context);

    // 7. 启动后处理
    afterRefresh(context, applicationArguments);

    // 8. 触发启动完成事件
    listeners.started(context);

    // 9. 执行Runner
    callRunners(context, applicationArguments);

    stopWatch.stop();
    return context;
}

4、关键步骤详解

4.1 环境准备

prepareEnvironment()方法:

  • 创建环境对象(StandardServletEnvironment/StandardEnvironment)
  • 配置PropertySources和Profiles
  • 处理命令行参数

4.2 创建应用上下文

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

  • Web应用:AnnotationConfigServletWebServerApplicationContext
  • 非Web应用:AnnotationConfigApplicationContext

4.3 刷新上下文

refreshContext()最终调用AbstractApplicationContext.refresh(),这是Spring容器的核心初始化过程:

java 复制代码
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新
        prepareRefresh();

        // 2. 获取BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 3. 准备BeanFactory
        prepareBeanFactory(beanFactory);

        try {
            // 4. 后置处理BeanFactory
            postProcessBeanFactory(beanFactory);

            // 5. 调用BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // 6. 注册BeanPostProcessor
            registerBeanPostProcessors(beanFactory);

            // 7. 初始化MessageSource
            initMessageSource();

            // 8. 初始化事件广播器
            initApplicationEventMulticaster();

            // 9. 初始化特殊Bean
            onRefresh();

            // 10. 注册监听器
            registerListeners();

            // 11. 初始化非延迟加载的单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // 12. 完成刷新
            finishRefresh();
        }
        // ...
    }
}

4.4 SpringBoot的自动配置

invokeBeanFactoryPostProcessors()会调用ConfigurationClassPostProcessor处理@Configuration类,其中关键的是处理@SpringBootApplication

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { /* ... */ })
public @interface SpringBootApplication {
    // ...
}

@EnableAutoConfiguration会导入AutoConfigurationImportSelector,它从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports加载自动配置类。


5、自定义启动过程

自定义Banner

在resources目录下创建banner.txt:

复制代码
  ___ _ __   ___| |_ ___ _ __ 
 / __| '_ \ / _ \ __/ _ \ '__|
 \__ \ |_) |  __/ ||  __/ |   
 |___/ .__/ \___|\__\___|_|   
     |_|

这个图案大家想放什么都可以。

自定义ApplicationContextInitializer:

java 复制代码
public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("MyInitializer initialize...");
    }
}

在META-INF/spring.factories中注册:

复制代码
org.springframework.context.ApplicationContextInitializer=com.example.MyInitializer

自定义SpringApplicationRunListener:

java 复制代码
public class MyRunListener implements SpringApplicationRunListener {
    public MyRunListener(SpringApplication application, String[] args) {}

    @Override
    public void starting() {
        System.out.println("MyRunListener starting...");
    }

    // 实现其他方法...
}

在META-INF/spring.factories中注册:

复制代码
org.springframework.boot.SpringApplicationRunListener=com.example.MyRunListener

自定义自动配置

创建自动配置类:

java 复制代码
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyProperties properties) {
        return new MyService(properties);
    }
}

在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中注册:

复制代码
com.example.MyAutoConfiguration

6、启动过程关键扩展点

  1. ApplicationContextInitializer: 在ConfigurableApplicationContext刷新之前执行
  2. ApplicationListener: 监听各种应用事件
  3. BeanFactoryPostProcessor: 修改BeanDefinition
  4. BeanPostProcessor: 修改Bean实例
  5. CommandLineRunner/ApplicationRunner: 应用启动后执行

7、关于调试的技巧

要深入理解启动过程,可以:

  1. 在关键类上设置断点:
    • SpringApplication.run()
    • AbstractApplicationContext.refresh()
    • ConfigurationClassPostProcessor.processConfigBeanDefinitions()
  2. 查看自动配置报告:
    • 启动时添加--debug参数
    • 或设置logging.level.org.springframework.boot.autoconfigure=DEBUG

通过以上分析,你应该对SpringBoot的启动过程有了全面的了解。实际开发中,可以根据需要自定义各个扩展点来满足特定需求。

相关推荐
IT_陈寒2 分钟前
JavaScript的异步地狱,我差点没爬出来
前端·人工智能·后端
NEGl DRYN3 分钟前
Go基础之环境搭建
开发语言·后端·golang
AI木马人5 分钟前
20.人工智能实战:大模型项目如何从 Demo 走向生产?一套可落地的上线验收清单与工程治理方案
java·开发语言·人工智能
CandyU27 分钟前
Unity —— 反射
java·开发语言
楼田莉子8 分钟前
仿照Muduo的高并发服务器:EventLoop模块及与TimeWheel模块联调
java·开发语言
小雅痞11 分钟前
[Java][Leetcode middle] 3. 无重复字符的最长子串
java·开发语言·leetcode
SamDeepThinking11 分钟前
为什么你做技术方案总是漏掉边界情况
java·后端·程序员
逻辑驱动的ken21 分钟前
Java高频面试考点场景题21
java·开发语言·面试·职场和发展·求职招聘
你好潘先生23 分钟前
Next.js + Spring Boot 实现 AI 多模型并行对话系统(架构设计与关键实现)
spring boot·向量检索·next.js·pgvector·ai对话·多模型对比·sse流式输出
苍煜23 分钟前
SpringBoot单体应用到分布式下的数据库锁、事务、Redis事务、分布式锁、分布式事务协调
数据库·spring boot·分布式