Spring Boot 启动流程详解 ⭐⭐⭐

面试题:Spring Boot 是如何启动的?

核心回答

Spring Boot 的启动流程从 SpringApplication.run() 方法开始,经历环境准备、应用上下文创建、Bean 加载、内嵌服务器启动等多个阶段。整个流程通过 SpringFactoriesLoader 实现自动配置,最终完成应用的启动。

一、启动入口:SpringApplication.run()

1.1 启动方法概览

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

1.2 SpringApplication 构造过程

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

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
    // 1. 推断应用类型(Servlet/Reactive/None)
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    
    // 2. 加载 Bootstrap 上下文初始化器
    this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
    
    // 3. 加载 ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
    // 4. 加载 ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
    // 5. 推断主类
    this.mainApplicationClass = deduceMainApplicationClass();
}

1.3 run() 方法核心流程

public ConfigurableApplicationContext run(String... args) {
    // 0. 记录启动时间
    long startTime = System.nanoTime();
    
    // 1. 创建 Bootstrap 上下文
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    ConfigurableApplicationContext context = null;
    try {
        // 2. 准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        
        // 3. 创建应用上下文
        context = createApplicationContext();
        
        // 4. 准备上下文
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        
        // 5. 刷新上下文(核心!)
        refreshContext(context);
        
        // 6. 刷新后处理
        afterRefresh(context, applicationArguments);
        
        // 7. 记录启动完成
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    return context;
}

二、准备环境:ConfigurableEnvironment

2.1 环境准备流程

┌─────────────────────────────────────────────────────────────┐
│                    环境准备流程                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. createEnvironment()                                     │
│     └── 创建 StandardServletEnvironment                     │
│                                                             │
│  2. configureEnvironment()                                  │
│     ├── 配置 PropertySources                                │
│     └── 添加命令行参数                                       │
│                                                             │
│  3. ConfigurationPropertySources.attach()                   │
│     └── 附加配置属性源                                       │
│                                                             │
│  4. listeners.environmentPrepared()                         │
│     └── 发布 ApplicationEnvironmentPreparedEvent            │
│                                                             │
│  5. bindToSpringApplication()                               │
│     └── 绑定环境到 SpringApplication                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.2 环境配置加载顺序

// 配置加载优先级(从高到低)
1. 命令行参数
2. JNDI 属性
3. Java 系统属性 (System.getProperties())
4. 操作系统环境变量
5. RandomValuePropertySource (random.*)
6. jar 包外的 application-{profile}.properties/yml
7. jar 包内的 application-{profile}.properties/yml
8. jar 包外的 application.properties/yml
9. jar 包内的 application.properties/yml
10. @PropertySource 注解
11. 默认属性

2.3 Environment 核心代码

protected ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                     DefaultBootstrapContext bootstrapContext,
                                                     ApplicationArguments applicationArguments) {
    // 创建环境对象
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 配置环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 附加配置属性源
    ConfigurationPropertySources.attach(environment);
    
    // 通知监听器环境已准备完成
    listeners.environmentPrepared(bootstrapContext, environment);
    
    // 绑定到 SpringApplication
    bindToSpringApplication(environment);
    
    return environment;
}

三、创建应用上下文

3.1 应用上下文类型推断

protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.create(this.webApplicationType);
}

// 根据应用类型创建不同的上下文
public enum WebApplicationType {
    NONE,           // 非Web应用
    SERVLET,        // Servlet Web应用
    REACTIVE;       // 响应式Web应用
}

// 类型推断逻辑
static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
        && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

3.2 常见应用上下文类型

应用类型 上下文类 说明
Servlet Web AnnotationConfigServletWebServerApplicationContext 传统 Spring MVC
Reactive AnnotationConfigReactiveWebServerApplicationContext WebFlux
Non-Web AnnotationConfigApplicationContext 纯后台应用

3.3 上下文创建流程

┌─────────────────────────────────────────────────────────────┐
│                 创建应用上下文流程                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 根据类型创建上下文实例                                     │
│     AnnotationConfigServletWebServerApplicationContext       │
│     ↓                                                       │
│  2. 注册 BeanFactoryPostProcessor                            │
│     ConfigurationClassPostProcessor                          │
│     AutowiredAnnotationBeanPostProcessor                     │
│     ↓                                                       │
│  3. 设置环境                                                 │
│     context.setEnvironment(environment)                      │
│     ↓                                                       │
│  4. 应用初始化器                                             │
│     applyInitializers(context)                               │
│     ↓                                                       │
│  5. 发布上下文准备事件                                       │
│     ApplicationContextInitializedEvent                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四、刷新上下文:refresh()

4.1 refresh() 核心流程

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // 1. 准备刷新:记录启动时间、初始化属性源
        prepareRefresh();

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

        // 3. 准备 BeanFactory:设置类加载器、添加后置处理器
        prepareBeanFactory(beanFactory);

        try {
            // 4. BeanFactory 后置处理(子类扩展点)
            postProcessBeanFactory(beanFactory);

            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");

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

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

            beanPostProcess.end();

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

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

            // 9. 初始化特殊 Bean(子类扩展)
            onRefresh();

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

            // 11. 完成单例 Bean 实例化
            finishBeanFactoryInitialization(beanFactory);

            // 12. 完成刷新:发布事件、清理缓存
            finishRefresh();

        } catch (BeansException ex) {
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
    }
}

4.2 refresh() 完整流程图

┌────────────────────────────────────────────────────────────────────┐
│                    refresh() 完整流程图                              │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│  prepareRefresh()                                                  │
│  ├── 初始化状态标识                                                 │
│  ├── 校验必要属性                                                   │
│  └── 初始化早期监听器                                               │
│     ↓                                                              │
│  obtainFreshBeanFactory()                                          │
│  ├── 刷新 BeanFactory                                              │
│  └── 返回 BeanFactory 实例                                         │
│     ↓                                                              │
│  prepareBeanFactory(beanFactory)                                   │
│  ├── 设置类加载器                                                   │
│  ├── 添加 BeanPostProcessor                                        │
│  └── 注册默认环境 Bean                                              │
│     ↓                                                              │
│  postProcessBeanFactory(beanFactory)                               │
│  └── 子类扩展点(如 WebApplicationContext 注册 Scope)              │
│     ↓                                                              │
│  invokeBeanFactoryPostProcessors(beanFactory)                      │
│  ├── 执行 BeanDefinitionRegistryPostProcessor                      │
│  │   └── ConfigurationClassPostProcessor 扫描配置类                │
│  └── 执行 BeanFactoryPostProcessor                                 │
│     └── PropertySourcesPlaceholderConfigurer 解析占位符            │
│     ↓                                                              │
│  registerBeanPostProcessors(beanFactory)                           │
│  ├── 注册 PriorityOrdered BeanPostProcessor                        │
│  ├── 注册 Ordered BeanPostProcessor                                │
│  └── 注册普通 BeanPostProcessor                                     │
│     ↓                                                              │
│  initMessageSource()                                               │
│  └── 初始化国际化消息源                                              │
│     ↓                                                              │
│  initApplicationEventMulticaster()                                 │
│  └── 初始化事件广播器                                                │
│     ↓                                                              │
│  onRefresh()                                                       │
│  └── 创建内嵌 Web 服务器(Tomcat/Jetty/Undertow)                    │
│     ↓                                                              │
│  registerListeners()                                               │
│  ├── 注册静态监听器                                                 │
│  └── 注册早期事件                                                   │
│     ↓                                                              │
│  finishBeanFactoryInitialization(beanFactory)                      │
│  ├── 初始化 ConversionService                                      │
│  ├── 冻结 BeanDefinition                                          │
│  └── 实例化所有非懒加载单例 Bean                                     │
│     ↓                                                              │
│  finishRefresh()                                                   │
│  ├── 清理缓存                                                       │
│  ├── 初始化 LifecycleProcessor                                     │
│  └── 发布 ContextRefreshedEvent                                    │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

4.3 关键步骤详解

4.3.1 invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 1. 执行 BeanDefinitionRegistryPostProcessor
    //    最重要的是 ConfigurationClassPostProcessor
    //    它负责解析 @Configuration、@ComponentScan、@Import 等注解
    
    // 执行顺序:
    // PriorityOrdered → Ordered → 普通
    
    // 2. 执行 BeanFactoryPostProcessor
    //    如 PropertySourcesPlaceholderConfigurer
    //    解析 ${...} 占位符
}

4.3.2 registerBeanPostProcessors

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 注册顺序:
    // 1. PriorityOrdered BeanPostProcessor
    //    - CommonAnnotationBeanPostProcessor (@PostConstruct, @PreDestroy)
    //    - AutowiredAnnotationBeanPostProcessor (@Autowired, @Value)
    
    // 2. Ordered BeanPostProcessor
    
    // 3. 普通 BeanPostProcessor
    //    - ApplicationContextAwareProcessor
    //    - ApplicationListenerDetector
    
    // 4. MergedBeanDefinitionPostProcessor
    //    - 收集 @Autowired 注解元数据
}

4.3.3 onRefresh()

// ServletWebServerApplicationContext
protected void onRefresh() {
    super.onRefresh();
    try {
        // 创建 Web 服务器
        createWebServer();
    } catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

private void createWebServer() {
    WebServer webServer = null;
    ServletContextInitializer servletContextInitializer = 
        this.selfInitializer;
    
    if (this.factory != null) {
        // 获取 WebServerFactory(Tomcat/Jetty/Undertow)
        webServer = getWebServer(servletContextInitializer);
    }
    
    this.webServer = webServer;
}

4.3.4 finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 1. 初始化 ConversionService
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
        beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class);
    }
    
    // 2. 冻结 BeanDefinition(不允许再修改)
    beanFactory.freezeConfiguration();
    
    // 3. 实例化所有非懒加载单例 Bean
    beanFactory.preInstantiateSingletons();
}

4.4 Bean 实例化流程

public void preInstantiateSingletons() throws BeansException {
    // 遍历所有 BeanDefinition
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        
        // 非抽象、单例、非懒加载
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // FactoryBean 处理
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            } else {
                // 普通 Bean
                getBean(beanName);
            }
        }
    }
}

// getBean() 核心流程
protected <T> T doGetBean(String name, Class<T> requiredType, 
                          Object[] args, boolean typeCheckOnly) {
    // 1. 转换 Bean 名称
    String beanName = transformedBeanName(name);
    
    // 2. 检查单例缓存
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null) {
        return (T) getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    
    // 3. 检查原型作用域循环依赖
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
    
    // 4. 检查父工厂
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    
    // 5. 标记 Bean 正在创建
    if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
    }
    
    try {
        // 6. 获取 BeanDefinition
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        
        // 7. 先实例化依赖 Bean
        String[] dependsOn = mbd.getDependsOn();
        for (String dep : dependsOn) {
            getBean(dep);
        }
        
        // 8. 创建 Bean 实例
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                return createBean(beanName, mbd, args);
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
    } finally {
        // 9. 清理
    }
    
    return (T) bean;
}

五、SpringFactoriesLoader 与自动配置

5.1 SpringFactoriesLoader 原理

public final class SpringFactoriesLoader {
    
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
    public static <T> List<T> loadFactories(Class<T> factoryType, ClassLoader classLoader) {
        // 1. 加载类名
        List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoader);
        
        // 2. 实例化
        List<T> result = new ArrayList<>(factoryImplementationNames.size());
        for (String factoryImplementationName : factoryImplementationNames) {
            result.add(instantiateFactory(factoryImplementationName, factoryType, classLoader));
        }
        
        return result;
    }
    
    public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        
        // 加载所有 META-INF/spring.factories 文件
        Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
        
        Properties properties = new Properties();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            properties.load(url.openStream());
        }
        
        // 返回指定类型的实现类名
        return Arrays.asList(properties.getProperty(factoryTypeName, "").split(","));
    }
}

5.2 spring.factories 示例

# org/springframework/boot/spring-boot-autoconfigure/3.x/spring.factories

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer

# Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundApplicationInitializer

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

5.3 自动配置流程

┌─────────────────────────────────────────────────────────────┐
│                    自动配置流程                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  @SpringBootApplication                                     │
│  └── @EnableAutoConfiguration                              │
│      └── @Import(AutoConfigurationImportSelector.class)    │
│          ↓                                                  │
│  AutoConfigurationImportSelector                           │
│  ├── getAutoConfigurationEntry()                           │
│  │   └── getCandidateConfigurations()                      │
│  │       └── SpringFactoriesLoader.loadFactoryNames()      │
│  │           └── 读取 META-INF/spring.factories            │
│  ↓                                                          │
│  过滤自动配置类                                              │
│  ├── @ConditionalOnClass                                   │
│  ├── @ConditionalOnBean                                    │
│  ├── @ConditionalOnMissingBean                             │
│  └── @ConditionalOnProperty                                │
│  ↓                                                          │
│  注册生效的自动配置类                                         │
│  └── BeanDefinition 注册到 BeanFactory                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.4 @EnableAutoConfiguration 详解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
    // 排除特定的自动配置类
    Class<?>[] exclude() default {};
    
    // 通过名称排除
    String[] excludeName() default {};
}

5.5 条件注解机制

// 条件注解示例
@Configuration
@ConditionalOnClass({ Servlet.class, ServletRegistration.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
public class WebMvcAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public InternalResourceViewResolver defaultViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(this.mvcProperties.getView().getPrefix());
        resolver.setSuffix(this.mvcProperties.getView().getSuffix());
        return resolver;
    }
}

// 常用条件注解
@ConditionalOnClass        // 类路径存在指定类
@ConditionalOnMissingClass // 类路径不存在指定类
@ConditionalOnBean         // 容器中存在指定 Bean
@ConditionalOnMissingBean  // 容器中不存在指定 Bean
@ConditionalOnProperty     // 配置属性满足条件
@ConditionalOnWebApplication // 是 Web 应用
@ConditionalOnExpression   // SpEL 表达式为 true

六、嵌入式 Web 服务器创建

6.1 Web 服务器工厂

// Tomcat
public class TomcatServletWebServerFactory implements ServletWebServerFactory {
    
    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        
        // 设置基础目录
        File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        
        // 创建 Connector
        Connector connector = new Connector(this.protocol);
        connector.setPort(this.port);
        tomcat.getService().addConnector(connector);
        
        // 创建 Context
        Context context = tomcat.addContext("", getDocumentBase());
        
        // 配置 Servlet
        configureContext(context, initializers);
        
        // 启动 Tomcat
        return getTomcatWebServer(tomcat);
    }
}

6.2 Web 服务器启动流程

┌─────────────────────────────────────────────────────────────┐
│                Web 服务器启动流程                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  onRefresh()                                                │
│  └── createWebServer()                                      │
│      └── ServletWebServerFactory.getWebServer()             │
│          ↓                                                  │
│  TomcatServletWebServerFactory                              │
│  ├── 创建 Tomcat 实例                                        │
│  ├── 配置 Connector(端口、协议)                            │
│  ├── 创建 Context(应用上下文)                              │
│  └── 返回 TomcatWebServer                                   │
│      ↓                                                      │
│  TomcatWebServer.start()                                    │
│  ├── tomcat.start()                                         │
│  ├── 初始化 Servlet                                         │
│  └── 启动监听线程                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.3 内嵌服务器配置

# application.yml
server:
  port: 8080
  servlet:
    context-path: /api
  tomcat:
    max-threads: 200
    min-spare-threads: 10
    accept-count: 100
    max-connections: 10000
  undertow:
    io-threads: 16
    worker-threads: 256
    buffer-size: 1024
@Configuration
public class TomcatConfig {
    
    @Bean
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory> 
        tomcatCustomizer() {
        return factory -> {
            factory.setPort(8081);
            factory.setContextPath("/app");
            
            TomcatConnectorCustomizer connectorCustomizer = connector -> {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
                protocol.setMaxThreads(200);
                protocol.setConnectionTimeout(30000);
            };
            factory.addConnectorCustomizers(connectorCustomizer);
        };
    }
}

七、完整启动流程图

┌─────────────────────────────────────────────────────────────────────┐
│                  Spring Boot 完整启动流程图                           │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  main()                                                             │
│  └── SpringApplication.run()                                        │
│      ↓                                                              │
│  【阶段一:创建 SpringApplication】                                   │
│  ├── 推断应用类型 (Servlet/Reactive/None)                           │
│  ├── 加载 ApplicationContextInitializer                             │
│  ├── 加载 ApplicationListener                                       │
│  └── 推断主类                                                       │
│      ↓                                                              │
│  【阶段二:运行 SpringApplication】                                   │
│  ├── 创建 BootstrapContext                                          │
│  ├── 准备环境 (ConfigurableEnvironment)                             │
│  │   ├── 加载配置文件 (application.yml)                             │
│  │   └── 绑定环境属性                                               │
│  ├── 打印 Banner                                                    │
│  └── 创建 ApplicationContext                                        │
│      ↓                                                              │
│  【阶段三:准备上下文】                                               │
│  ├── 设置环境                                                       │
│  ├── 执行 ApplicationContextInitializer                             │
│  ├── 发布 ApplicationContextInitializedEvent                        │
│  └── 加载 BeanDefinition                                           │
│      ↓                                                              │
│  【阶段四:刷新上下文】                                               │
│  ├── prepareRefresh()                                               │
│  ├── obtainFreshBeanFactory()                                       │
│  ├── prepareBeanFactory()                                           │
│  ├── invokeBeanFactoryPostProcessors()                              │
│  │   ├── ConfigurationClassPostProcessor                            │
│  │   │   ├── 解析 @Configuration                                    │
│  │   │   ├── 解析 @ComponentScan                                    │
│  │   │   ├── 解析 @Import                                          │
│  │   │   └── 注册 BeanDefinition                                   │
│  │   └── 处理自动配置                                               │
│  ├── registerBeanPostProcessors()                                   │
│  ├── initMessageSource()                                            │
│  ├── initApplicationEventMulticaster()                              │
│  ├── onRefresh()                                                    │
│  │   └── 创建内嵌 Web 服务器                                        │
│  ├── registerListeners()                                            │
│  ├── finishBeanFactoryInitialization()                              │
│  │   └── 实例化所有单例 Bean                                        │
│  └── finishRefresh()                                                │
│      └── 发布 ContextRefreshedEvent                                 │
│      ↓                                                              │
│  【阶段五:启动完成】                                                 │
│  ├── 执行 CommandLineRunner                                         │
│  ├── 执行 ApplicationRunner                                         │
│  ├── 发布 ApplicationStartedEvent                                   │
│  └── 应用就绪                                                       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

八、启动扩展点

8.1 ApplicationContextInitializer

public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        // 在上下文刷新之前执行
        ConfigurableEnvironment env = applicationContext.getEnvironment();
        env.getSystemProperties().put("my.property", "value");
    }
}

// 注册方式
// 1. spring.factories
org.springframework.context.ApplicationContextInitializer=\
com.example.MyInitializer

// 2. SpringApplication.addInitializers()
SpringApplication app = new SpringApplication(Application.class);
app.addInitializers(new MyInitializer());

8.2 ApplicationListener

public class MyListener implements ApplicationListener<ApplicationStartedEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("应用启动完成!");
    }
}

// 常用事件
ApplicationStartingEvent          // 启动开始
ApplicationEnvironmentPreparedEvent // 环境准备完成
ApplicationContextInitializedEvent // 上下文初始化
ApplicationPreparedEvent          // 上下文准备完成
ApplicationStartedEvent           // 启动完成
ApplicationReadyEvent             // 就绪

8.3 CommandLineRunner / ApplicationRunner

@Component
public class MyRunner implements CommandLineRunner {
    
    @Override
    public void run(String... args) throws Exception {
        // 应用启动后执行
        System.out.println("执行初始化任务...");
    }
}

@Component
public class MyAppRunner implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 支持解析命令行参数
        List<String> files = args.getOptionValues("file");
    }
}

📖 高频面试题

Q1: Spring Boot 启动流程是怎样的?

答: Spring Boot 启动流程分为以下几个阶段:

1. 创建 SpringApplication

2. 运行 SpringApplication

3. 准备上下文

4. 刷新上下文(核心)

5. 启动完成

Q2: @EnableAutoConfiguration 是如何工作的?

答:

1. 工作原理

@EnableAutoConfiguration
  └── @Import(AutoConfigurationImportSelector.class)
      └── selectImports()
          └── SpringFactoriesLoader.loadFactoryNames()
              └── 读取 META-INF/spring.factories

2. 加载过程

3. 条件注解

4. 排除自动配置

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
// 或
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
// 或
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Q3: Spring Boot 如何创建内嵌 Tomcat?

答:

1. 触发时机

2. 创建流程

// ServletWebServerApplicationContext
protected void onRefresh() {
    createWebServer();
}

private void createWebServer() {
    ServletWebServerFactory factory = getWebServerFactory();
    this.webServer = factory.getWebServer(this.selfInitializer);
}

3. 工厂选择

4. 条件判断

Q4: SpringFactoriesLoader 的作用?

答:

1. 作用

2. 使用场景

3. 文件格式

# key = 接口全限定名
# value = 实现类全限定名(多个用逗号分隔)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

4. Spring Boot 2.7+ 变化

Q5: Spring Boot 如何实现零配置?

答:

1. 约定优于配置

2. 自动配置

3. Starter 机制

4. 配置覆盖


参考链接: