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的启动过程有了全面的了解。实际开发中,可以根据需要自定义各个扩展点来满足特定需求。

相关推荐
Han.miracle2 小时前
Java 8 Lambda 表达式与方法引用的语法优化及实战应用研究
java·开发语言·jvm
y1y1z2 小时前
Spring OAuth 2.0 教程
java·后端·spring
风象南2 小时前
Spring Boot 实现单账号登录控制
后端
chenyuhao20242 小时前
Linux系统编程:进程控制
linux·运维·服务器·开发语言·c++·后端
代龙涛2 小时前
wordpress目录介绍
开发语言·后端·php
小年糕是糕手2 小时前
【C++】模板初阶
java·开发语言·javascript·数据结构·c++·算法·leetcode
Victor3562 小时前
Netty(4)Netty的Channel是什么?它有哪些类型?
后端
路边草随风2 小时前
java发送飞书消息卡片
java·飞书
是梦终空3 小时前
JAVA毕业设计253—基于Java+Springboot+vue3+协同过滤推荐算法的传统服饰文化平台(源代码+数据库+任务书+12000字论文)
java·spring boot·vue·毕业设计·课程设计·协同过滤推荐算法·传统服饰文化平台