Spring Boot启动魔法:SpringApplication.run()源码全流程拆解

引言

在Spring Boot应用中,SpringApplication.run()方法是整个应用启动的核心入口。理解其内部实现机制,不仅有助于我们更好地掌握Spring Boot的自动配置原理,还能帮助我们在实际开发中进行性能优化和问题排查。本文将深入解析SpringApplication.run()的源码实现,从初始化到上下文刷新的全流程,揭示Spring Boot启动背后的"魔法"。

一、SpringApplication.run()方法概览

1.1 方法定义

在Spring Boot 3.2.x版本中,SpringApplication.run()方法的定义如下:

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

这个方法看似简单,实际上包含了Spring Boot启动的完整流程。它主要完成以下核心工作:

  1. 推断应用类型:确定应用是Servlet、Reactive还是None
  2. 加载并初始化工厂配置 :扫描并加载META-INF/spring/目录下的工厂配置文件
  3. 准备运行时环境:包括属性源、配置文件等的加载和初始化
  4. 创建并配置应用上下文:初始化Spring的应用上下文
  5. 执行自动配置:根据条件装配需要的Bean
  6. 启动内嵌服务器:如Tomcat等Web服务器

1.2 启动流程的关键参与者

在整个启动过程中,以下组件扮演着关键角色:

  1. SpringApplication:启动流程的控制器,协调各个组件的初始化和运行
  2. Environment:环境抽象,包含配置属性、profiles等信息
  3. ApplicationContext:Spring容器的核心接口,管理Bean的生命周期
  4. BeanFactoryPostProcessor:Bean定义的后处理器,允许修改Bean的元数据
  5. ApplicationRunner/CommandLineRunner:启动后回调接口,允许在应用启动后执行特定逻辑

二、SpringApplication初始化详解

2.1 primarySources:主配置类的旅程

primarySourcesSpringApplication构造方法中最重要的参数之一,它代表了应用的主配置类,也就是我们的启动类。例如:

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

让我们追踪primarySource的完整旅程:

java 复制代码
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class[]{primarySource}, args);
}
java 复制代码
public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}
java 复制代码
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 其他初始化
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    // 其他初始化操作
}

关键说明

  1. 唯一性保证 :将传入的主配置类转换为Set集合,确保唯一性
  2. 顺序保持 :通过LinkedHashSet保持原始顺序,这对某些需要顺序保证的配置场景非常重要
  3. 自动配置基础:作为后续自动配置和组件扫描的基础
  4. 设计优势 :使用Set可以避免重复配置类导致的潜在问题,同时LinkedHashSet又能保持初始顺序

2.2 其他关键初始化操作

2.2.1 推断应用类型

java 复制代码
this.webApplicationType = WebApplicationType.deduceFromClasspath();

判断逻辑

  • 如果存在DispatcherHandler且不存在DispatcherServletREACTIVE
  • 如果存在Servlet相关类则不是REACTIVESERVLET
  • 否则 → NONE

这个判断决定了后续创建的应用上下文类型和内嵌服务器的选择。

2.2.2 推导主应用类

java 复制代码
this.mainApplicationClass = this.deduceMainApplicationClass();

说明 :SpringApplication会尝试推导主应用类,主要作用于没有明确指定primarySources的时候。推导逻辑基于堆栈跟踪分析,查找包含main方法的类。这个设计体现了Spring Boot的"智能默认值"哲学:尽可能减少必须配置的参数。

2.2.3 资源加载器配置

java 复制代码
this.resourceLoader = resourceLoader;

说明 :支持自定义ResourceLoader,这在需要特殊资源加载策略的场景下非常有用。如果没有显式指定,Spring Boot会使用默认的DefaultResourceLoader

三、run()方法执行流程拆解

run()方法的执行流程可分为以下六个关键阶段:

  1. 准备环境(prepareEnvironment)
  2. 创建应用上下文(createApplicationContext)
  3. 准备上下文(prepareContext)
  4. 刷新上下文(refreshContext)
  5. 后置处理(afterRefresh)
  6. 启动完成(事件发布)

让我们看看完整的run()方法实现:

java 复制代码
public ConfigurableApplicationContext run(String... args) {
    Startup startup = SpringApplication.Startup.create();
    if (this.registerShutdownHook) {
        shutdownHook.enableShutdownHookAddition();
    }
    // 创建引导上下文
    DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
    ConfigurableApplicationContext context = null;
    this.configureHeadlessProperty();
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    Throwable ex;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 准备环境
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        // Spring Boot启动的时候会打印Spring Boot的标志以及对应的版本
        Banner printedBanner = this.printBanner(environment);
        // 创建应用上下文
        context = this.createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        // 准备上下文
        this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 刷新上下文(关键)
        this.refreshContext(context);
        // 后置处理
        this.afterRefresh(context, applicationArguments);
        // 其他
    } catch (Throwable ex) {
        // 异常处理逻辑
    }
    return context;
}

3.1 阶段一:准备环境(prepareEnvironment)

环境准备是启动流程的第一步,它负责创建和配置应用的运行环境。

java 复制代码
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, 
                                                   DefaultBootstrapContext bootstrapContext, 
                                                   ApplicationArguments applicationArguments) {
    ConfigurableEnvironment environment = this.getOrCreateEnvironment();
    this.configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    listeners.environmentPrepared(bootstrapContext, environment);
    DefaultPropertiesPropertySource.moveToEnd(environment);
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"), 
                 "Environment prefix cannot be set via properties.");
    this.bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());
        environment = environmentConverter.convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

3.1.1 getOrCreateEnvironment()

作用:根据应用的类型创建相应的环境实例:

  • 非Web应用StandardEnvironment
  • Servlet Web应用StandardServletEnvironment
  • Reactive Web应用StandardReactiveWebEnvironment

若已存在环境实例(如自定义环境),则直接复用,保证单例性。

3.1.2 configureEnvironment()

作用

  • 解析命令行参数(applicationArguments.getSourceArgs())并添加到环境的属性源(PropertySource
  • 激活指定的Profiles(如通过spring.profiles.active配置)
  • 配置环境的系统属性、环境变量等默认属性源

3.1.3 ConfigurationPropertySources.attach(environment)

核心作用 :将环境中的PropertySource包装为ConfigurationPropertySource,并注册到环境中。

设计意图 :为@ConfigurationProperties注解提供支持。Spring Boot通过ConfigurationPropertySource实现配置属性的类型安全绑定(而非直接解析原始PropertySource)。

3.1.4 DefaultPropertiesPropertySource.moveToEnd(environment)

作用 :将默认属性源移到属性源链的最后,保证用户配置(如application.properties、命令行参数)的优先级高于框架默认值,避免默认值覆盖用户配置。

设计原则:体现了Spring Boot"约定优于配置"的理念,同时确保用户配置始终优先。

3.1.5 bindToSpringApplication(environment)

作用 :将环境中的属性(如spring.main.*配置)绑定到SpringApplication实例的成员变量。

示例 :环境中的spring.main.banner-mode=off会被绑定到SpringApplicationbannerMode属性,控制启动Banner是否显示。

3.2 阶段二:创建应用上下文(createApplicationContext)

根据不同的Web应用类型,Spring Boot会创建不同类型的应用上下文:

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

抽象逻辑

java 复制代码
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
    switch (webApplicationType) {
        case SERVLET: 
            return new AnnotationConfigServletWebServerApplicationContext();
        case REACTIVE: 
            return new AnnotationConfigReactiveWebServerApplicationContext();
        default: 
            return new AnnotationConfigApplicationContext();
    }
};

说明

  • SERVLET类型 :创建AnnotationConfigServletWebServerApplicationContext,支持Servlet Web应用
  • REACTIVE类型 :创建AnnotationConfigReactiveWebServerApplicationContext,支持响应式Web应用
  • NONE类型 :创建AnnotationConfigApplicationContext,普通应用上下文

3.3 阶段三:准备应用上下文(prepareContext)

准备上下文阶段是连接环境配置和上下文刷新的桥梁,它完成了大量的初始化工作:

java 复制代码
private void prepareContext(DefaultBootstrapContext bootstrapContext,
                            ConfigurableApplicationContext context,
                            ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners,
                            ApplicationArguments applicationArguments,
                            Banner printedBanner) {
    context.setEnvironment(environment);
    this.postProcessApplicationContext(context);
    this.addAotGeneratedInitializerIfNecessary(this.initializers);
    this.applyInitializers(context);
    listeners.contextPrepared(context);
    bootstrapContext.close(context);
    if (this.logStartupInfo) {
        this.logStartupInfo(context.getParent() == null);
        this.logStartupProfileInfo(context);
    }

    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }

    if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
        autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
        if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
            listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
    }

    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }

    if (this.keepAlive) {
        context.addApplicationListener(new KeepAlive());
    }

    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    if (!AotDetector.useGeneratedArtifacts()) {
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
    }

    listeners.contextLoaded(context);
}

3.3.1 绑定环境到上下文

java 复制代码
context.setEnvironment(environment);

作用:将之前准备好的环境实例(包含属性源、Profiles等)关联到应用上下文。

设计意图 :上下文后续解析Bean定义、处理@Value注解、@ConfigurationProperties时,需通过环境获取配置属性,因此这是上下文与环境的核心绑定步骤。

3.3.2 后置处理应用上下文

java 复制代码
this.postProcessApplicationContext(context);

作用:对上下文进行定制化后置处理,典型操作包括:

  • 设置上下文的BeanNameGenerator(默认AnnotationBeanNameGenerator,用于生成Bean名称)
  • 设置上下文的ResourceLoader(资源加载器,用于读取类路径/文件资源)
  • 若启用@EnableAspectJAutoProxy,配置AOP相关的BeanPostProcessor
  • 为上下文添加ConversionService(类型转换服务)

3.3.3 应用初始化器

java 复制代码
this.applyInitializers(context);

作用 :应用所有的ApplicationContextInitializer,对上下文进行进一步的初始化。这些初始化器可以通过META-INF/spring.factoriesMETA-INF/spring/org.springframework.context.ApplicationContextInitializer文件注册。

3.3.4 打印启动日志信息

java 复制代码
if (this.logStartupInfo) {
    this.logStartupInfo(context.getParent() == null);
    this.logStartupProfileInfo(context);
}

说明

  • logStartupInfo:控制是否打印启动信息(默认开启),包括Spring Boot版本、应用名称等
  • logStartupProfileInfo:打印当前激活的Profiles(如The following 1 profile is active: "dev"
  • 作用:提升启动过程的可观测性,方便开发者调试

3.3.5 注册核心单例Bean

java 复制代码
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
    beanFactory.registerSingleton("springBootBanner", printedBanner);
}

作用 :将ApplicationArguments(应用参数)和Banner(启动横幅)注册为上下文的单例Bean,开发者可通过@Autowired直接注入使用。

3.3.6 配置BeanFactory特性

java 复制代码
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
    autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
    if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
        listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
}

说明

  • 允许循环依赖setAllowCircularReferences(默认值由Spring Boot版本决定,2.6+默认关闭),控制是否允许Bean之间的循环依赖(如A依赖B,B依赖A)
  • 允许Bean定义覆盖setAllowBeanDefinitionOverriding(默认false),控制是否允许后注册的BeanDefinition覆盖之前的同名Bean(如多模块下重复定义Bean)

设计意图:通过配置BeanFactory的核心特性,适配不同的开发场景需求。

3.3.7 启用懒初始化

java 复制代码
if (this.lazyInitialization) {
    context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}

说明

  • 懒初始化 :通过LazyInitializationBeanFactoryPostProcessor实现,所有Bean默认延迟到首次使用时创建(而非上下文刷新时立即创建)
  • 作用:减少应用启动时间,适用于Bean数量多、启动慢的场景(但需注意懒加载可能导致问题延迟暴露)

3.3.8 注册KeepAlive监听器

java 复制代码
if (this.keepAlive) {
    context.addApplicationListener(new KeepAlive());
}

说明

  • KeepAlive:Spring Boot开发环境的热重载/重启支持组件
  • 作用:保持应用进程存活,配合DevTools实现代码修改后的自动重启

3.3.9 处理属性源顺序

java 复制代码
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));

说明

  • PropertySourceOrderingBeanFactoryPostProcessor:用于调整上下文环境中属性源的优先级顺序
  • 设计意图 :保证用户配置(如application.yml)优先级高于框架默认配置,符合Spring Boot"约定优于配置"的原则

3.3.10 加载源配置

java 复制代码
if (!AotDetector.useGeneratedArtifacts()) {
    Set<Object> sources = this.getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    this.load(context, sources.toArray(new Object[0]));
}

作用:加载所有配置源(包括主配置类),将它们注册为Bean定义。这是自动配置和组件扫描的基础。

3.4 阶段四:刷新上下文(refreshContext)

刷新上下文是整个启动流程中最核心、最复杂的阶段。它调用了Spring框架的refresh()方法,完成了Bean的加载、解析、实例化等所有工作。

java 复制代码
public void refresh() throws BeansException, IllegalStateException {
    this.startupShutdownLock.lock();

    try {
        this.startupShutdownThread = Thread.currentThread();
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (Error | RuntimeException var12) {
            Throwable ex = var12;
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
            }

            this.destroyBeans();
            this.cancelRefresh(ex);
            throw ex;
        } finally {
            contextRefresh.end();
        }
    } finally {
        this.startupShutdownThread = null;
        this.startupShutdownLock.unlock();
    }
}

refresh()方法包含12个标准步骤(Spring框架核心):

  1. prepareRefresh:准备刷新上下文
  2. obtainFreshBeanFactory:获取新的BeanFactory
  3. prepareBeanFactory:准备BeanFactory
  4. postProcessBeanFactory:后置处理BeanFactory
  5. invokeBeanFactoryPostProcessors:执行BeanFactory后置处理器
  6. registerBeanPostProcessors:注册Bean后置处理器
  7. initMessageSource:初始化消息源
  8. initApplicationEventMulticaster:初始化事件广播器
  9. onRefresh:模板方法(Spring Boot扩展点)
  10. registerListeners:注册监听器
  11. finishBeanFactoryInitialization:完成Bean初始化
  12. finishRefresh:完成刷新

其中,Spring Boot在onRefresh阶段完成了内嵌容器的启动。

3.4.1 refreshContext阶段最关键的三个扩展点

问题refreshContext()阶段最关键的三个扩展点是什么?

答案

  1. invokeBeanFactoryPostProcessors(执行自动配置)
  2. onRefresh(内嵌服务器启动)
  3. finishBeanFactoryInitialization(单例Bean初始化)

这三个步骤分别承担配置解析与自动配置、内嵌服务器启动、单例Bean初始化的核心职责。下面我们逐一解析它们的实现逻辑。

扩展点一:invokeBeanFactoryPostProcessors - 执行自动配置

invokeBeanFactoryPostProcessors(beanFactory)的核心作用是执行所有BeanFactoryPostProcessor接口的实现类。这类处理器可以在Bean定义加载完成后、Bean实例化前修改BeanFactory或Bean定义,Spring Boot的自动配置正是通过这个机制触发的

1. 框架层核心实现(AbstractApplicationContext)

java 复制代码
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 核心方法:执行BeanFactoryPostProcessor
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    // 检测LoadTimeWeaver并注册临时ClassLoader(AOP相关)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors会按优先级顺序执行BeanFactoryPostProcessor

  • 先执行PriorityOrdered接口的实现类
  • 再执行Ordered接口的实现类
  • 最后执行普通的BeanFactoryPostProcessor

2. Spring Boot自动配置的触发(关键扩展)

Spring Boot的自动配置核心依赖ConfigurationClassPostProcessor(Spring框架内置的BeanFactoryPostProcessor,实现了PriorityOrdered),它会在这一步被执行,具体逻辑:

java 复制代码
// ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 1. 扫描所有@Configuration类(包括Spring Boot启动类)
    List<BeanDefinitionHolder> configCandidates = findCandidateConfigClasses(registry, metadataReaderFactory);
    // 2. 解析每个@Configuration类:处理@ComponentScan、@Import、@Bean等注解
    for (BeanDefinitionHolder holder : configCandidates) {
        ConfigurationClass configClass = new ConfigurationClass(holder.getBeanDefinition(), metadataReaderFactory);
        parser.parse(configClass); // 解析配置类
        parser.validate();
        configurationClasses.put(configClass, configClass);
    }
    // 3. 处理导入的配置类(关键:Spring Boot的自动配置通过@Import(AutoConfigurationImportSelector.class)触发)
    this.reader.loadBeanDefinitions(configurationClasses);
}

关键点

  • AutoConfigurationImportSelector :Spring Boot启动类的@SpringBootApplication注解包含@EnableAutoConfiguration,而@EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)导入自动配置类
  • 自动配置类加载AutoConfigurationImportSelector.selectImports()会读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件(Spring Boot 2.7+),加载所有候选自动配置类(如DataSourceAutoConfigurationTomcatServletWebServerFactoryAutoConfiguration),并根据条件注解(@ConditionalOnClass@ConditionalOnMissingBean等)筛选生效的配置类,最终注册为BeanDefinition

总结invokeBeanFactoryPostProcessors通过执行ConfigurationClassPostProcessor,完成Spring Boot自动配置类的扫描、解析与注册,为后续Bean实例化奠定基础。

扩展点二:onRefresh - 启动内嵌服务器

onRefresh()AbstractApplicationContext的模板方法(空实现),子类(如Spring Boot的ServletWebServerApplicationContext)会重写此方法,核心职责是创建并启动内嵌Web服务器(Tomcat/Jetty/Undertow)。

1. 框架层定义(AbstractApplicationContext)

java 复制代码
protected void onRefresh() throws BeansException {
    // 空模板方法,由子类扩展
}

2. Spring Boot的扩展实现(ServletWebServerApplicationContext)

java 复制代码
@Override
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 = this.webServer;
    ServletContext servletContext = getServletContext();
    if (webServer == null && servletContext == null) {
        // 1. 获取WebServerFactory(由自动配置类提供,如TomcatServletWebServerFactory)
        ServletWebServerFactory factory = getWebServerFactory();
        // 2. 创建WebServer(如TomcatWebServer)
        this.webServer = factory.getWebServer(getSelfInitializer());
        // 3. 注册ApplicationContext到ServletContext(供ServletContextAware组件使用)
        getBeanFactory().registerSingleton("webServerGracefulShutdown", 
            new WebServerGracefulShutdownLifecycle(this.webServer));
        getBeanFactory().registerSingleton("webServerStartStop", 
            new WebServerStartStopLifecycle(this, this.webServer));
    } else if (servletContext != null) {
        try {
            getSelfInitializer().onStartup(servletContext);
        } catch (ServletException ex) {
            throw new ApplicationContextException("Cannot initialize servlet context", ex);
        }
    }
    initPropertySources();
}

说明

  • WebServerFactory获取getWebServerFactory()会从BeanFactory中获取ServletWebServerFactory类型的Bean(由TomcatServletWebServerFactoryAutoConfiguration等自动配置类注册)
  • WebServer创建factory.getWebServer()会根据工厂类型创建对应的服务器实例(如TomcatWebServer会初始化Tomcat的Tomcat对象,配置连接器、引擎等)
  • 服务器启动WebServerStartStopLifecycle会在上下文刷新完成后触发webServer.start(),启动内嵌服务器(绑定端口、监听请求)

总结 :Spring Boot通过重写onRefresh()方法,在上下文刷新阶段创建并启动内嵌Web服务器,实现"一键启动Web应用"的特性。

扩展点三:finishBeanFactoryInitialization - 初始化所有单例Bean

finishBeanFactoryInitialization(beanFactory)refresh()的核心步骤,负责初始化所有非懒加载的单例Bean(实例化、属性填充、初始化方法调用),Spring Boot自动配置的Bean(如DataSource、JdbcTemplate)都会在此阶段完成初始化

1. 框架层核心实现(AbstractApplicationContext)

java 复制代码
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 1. 初始化ConversionService(类型转换服务)
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }
    // 2. 注册嵌入式值解析器(处理@Value中的${}占位符)
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }
    // 3. 初始化LoadTimeWeaverAwareBean(AOP织入相关)
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }
    // 4. 冻结Bean定义(禁止修改BeanDefinition)
    beanFactory.freezeConfiguration();
    // 5. 核心:初始化所有非懒加载的单例Bean
    beanFactory.preInstantiateSingletons();
}

2. 单例Bean初始化的核心逻辑(DefaultListableBeanFactory.preInstantiateSingletons)

java 复制代码
@Override
public void preInstantiateSingletons() throws BeansException {
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // 遍历所有BeanDefinition名称
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 跳过抽象Bean、非单例Bean、懒加载Bean
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // 处理FactoryBean:先初始化FactoryBean本身,再通过getObject()获取实际Bean
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            } else {
                // 核心:初始化普通Bean
                getBean(beanName);
            }
        }
    }
    // 触发SmartInitializingSingleton的afterSingletonsInstantiated方法
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            smartSingleton.afterSingletonsInstantiated();
        }
    }
}

3. Bean初始化的完整流程(getBean(beanName)的底层逻辑)

当调用getBean(beanName)时,会触发Bean的完整生命周期:

  1. 实例化 :通过反射或工厂方法创建Bean实例(AbstractAutowireCapableBeanFactory.createBeanInstance
  2. 属性填充 :将依赖的Bean(如@Autowired标注的属性)注入到当前Bean(populateBean
  3. 初始化
    • 执行BeanNameAwareApplicationContextAware等Aware接口的方法
    • 执行BeanPostProcessor.postProcessBeforeInitialization(如AutowiredAnnotationBeanPostProcessor处理@Value
    • 执行@PostConstruct注解的方法或init-method配置的初始化方法(invokeInitMethods
    • 执行BeanPostProcessor.postProcessAfterInitialization(如AOP的动态代理创建)
  4. 注册DisposableBean :若Bean实现DisposableBean或配置destroy-method,注册销毁回调

Spring Boot的特殊处理 :自动配置的Bean(如DataSource)会在此阶段完成初始化。DataSourceAutoConfiguration注册的DataSource BeanDefinition会被实例化,通过@ConfigurationProperties绑定application.properties中的数据库配置(如spring.datasource.url),最终生成可用的DataSource实例。

总结finishBeanFactoryInitialization通过preInstantiateSingletons()完成所有非懒加载单例Bean的初始化,是Spring容器"依赖注入"和"Bean实例化"的最终落地步骤。

3.5 阶段五:后置处理(afterRefresh)

在上下文刷新完成后,Spring Boot会执行后置处理:

java 复制代码
private void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
    callRunners(context, args);
}

作用 :调用所有实现了ApplicationRunnerCommandLineRunner接口的Bean,执行其run()方法。这些Runner允许开发者在应用完全启动后执行特定的初始化逻辑。

3.6 阶段六:启动完成(事件发布)

在应用上下文刷新和后置处理完成后,Spring Boot会发布以下事件:

  • ApplicationStartedEvent:应用已启动(上下文已刷新)
  • ApplicationReadyEvent:应用已就绪(所有Runner已执行)

这些事件可以被ApplicationListener监听,用于执行启动后的自定义逻辑。

四、invokeBeanFactoryPostProcessors与AutoConfigurationImportSelector的深度联动

要理解invokeBeanFactoryPostProcessorsAutoConfigurationImportSelector的深度联动,需从触发链路、注解解析、自动配置类加载、BeanDefinition注册四个维度拆解,明确两者如何协作完成Spring Boot的自动配置核心逻辑。

4.1 联动起点:invokeBeanFactoryPostProcessors触发ConfigurationClassPostProcessor执行

invokeBeanFactoryPostProcessors是整个联动的入口,其核心是通过PostProcessorRegistrationDelegate按优先级执行BeanFactoryPostProcessor

  • 优先级触发规则ConfigurationClassPostProcessor实现了PriorityOrdered接口,因此会被优先执行(这是联动的前提,保证自动配置逻辑在其他BeanFactoryPostProcessor前完成)
  • 执行入口PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors会调用ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry方法,进而触发其核心逻辑processConfigBeanDefinitions

4.2 关键桥梁:ConfigurationClassPostProcessor解析@EnableAutoConfiguration与@Import

ConfigurationClassPostProcessorprocessConfigBeanDefinitions方法是连接两者的核心桥梁,它在解析Spring Boot启动类时,会触发对AutoConfigurationImportSelector的调用。

4.2.1 扫描启动类(@SpringBootApplication)

Spring Boot启动类标注的@SpringBootApplication是一个复合注解,包含:

java 复制代码
@SpringBootConfiguration // 本质是@Configuration
@EnableAutoConfiguration  // 关键:触发自动配置
@ComponentScan            // 组件扫描

ConfigurationClassPostProcessor会将启动类识别为@Configuration类(候选配置类),进入解析流程。

4.2.2 解析@EnableAutoConfiguration注解

@EnableAutoConfiguration的核心源码:

java 复制代码
@Import(AutoConfigurationImportSelector.class) // 导入AutoConfigurationImportSelector
public @interface EnableAutoConfiguration { ... }

ConfigurationClassPostProcessor在解析@EnableAutoConfiguration时,会处理其中的@Import注解:

当遇到@Import导入的是ImportSelector类型(AutoConfigurationImportSelector实现了ImportSelector),会调用其selectImports方法,获取需要导入的配置类名称。

4.3 核心协作:AutoConfigurationImportSelector加载并筛选自动配置类

ConfigurationClassPostProcessor调用AutoConfigurationImportSelector.selectImports,这是联动的核心环节,AutoConfigurationImportSelector在此完成自动配置类的加载与筛选。

4.3.1 加载候选自动配置类

selectImports的核心逻辑依赖AutoConfigurationImportSelector.AutoConfigurationGroup(内部类)的process方法:

java 复制代码
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
    // 1. 读取候选自动配置类列表
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 2. 去重、排序、应用排除规则(@SpringBootApplication(exclude = ...))
    configurations = removeDuplicates(configurations);
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    configurations.removeAll(exclusions);
    // 3. 条件筛选:根据@Conditional注解判断配置类是否生效
    configurations = getConfigurationClassFilter().filter(configurations);
    // 4. 记录自动配置报告(供启动日志输出)
    fireAutoConfigurationImportEvents(configurations, exclusions);
    this.entries.putIfAbsent(annotationMetadata, new Entry(configurations, exclusions));
}

关键点

  • getCandidateConfigurations :通过SpringFactoriesLoader读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件(Spring Boot 2.7+),获取所有候选自动配置类(如DataSourceAutoConfigurationWebMvcAutoConfiguration
  • 条件筛选 :通过ConfigurationClassFilter(默认是OnClassCondition)结合@ConditionalOnClass@ConditionalOnMissingBean等注解,筛选出当前环境下生效的自动配置类(例如:若项目中没有Tomcat依赖,TomcatServletWebServerFactoryAutoConfiguration会被过滤)

4.3.2 返回生效配置类名称

AutoConfigurationImportSelector最终将筛选后的自动配置类名称返回给ConfigurationClassPostProcessor

4.4 收尾联动:ConfigurationClassPostProcessor注册自动配置类为BeanDefinition

ConfigurationClassPostProcessor拿到AutoConfigurationImportSelector返回的生效配置类名称后,会继续完成:

  1. 解析自动配置类 :将每个自动配置类(如DataSourceAutoConfiguration)作为@Configuration类解析,处理其内部的@Bean@Conditional等注解
  2. 注册BeanDefinition :通过ConfigurationClassBeanDefinitionReader将自动配置类中的Bean定义(如DataSourceJdbcTemplate)注册到BeanFactory

至此,invokeBeanFactoryPostProcessors通过触发ConfigurationClassPostProcessor,联动AutoConfigurationImportSelector完成了自动配置类的加载、筛选、解析与注册,为后续finishBeanFactoryInitialization阶段的Bean实例化奠定基础。

4.5 联动逻辑总结(时序图简化)

java 复制代码
invokeBeanFactoryPostProcessors
    ↓ 触发PriorityOrdered的BeanFactoryPostProcessor
    ConfigurationClassPostProcessor.processConfigBeanDefinitions
        ↓ 解析启动类的@SpringBootApplication
        ↓ 解析@EnableAutoConfiguration中的@Import(AutoConfigurationImportSelector)
        AutoConfigurationImportSelector.selectImports
            ↓ 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
            ↓ 条件筛选生效的自动配置类
        ↓ 返回生效配置类列表
    ConfigurationClassPostProcessor注册自动配置类为BeanDefinition

4.6 关键设计亮点

  1. 分层解耦invokeBeanFactoryPostProcessors负责触发后置处理器,ConfigurationClassPostProcessor负责配置类解析,AutoConfigurationImportSelector专注于自动配置类加载------职责分离,符合单一原则
  2. 扩展性 :通过ImportSelector接口,Spring Boot将自动配置逻辑与配置类解析逻辑解耦,开发者可自定义ImportSelector扩展自动配置
  3. 条件控制AutoConfigurationImportSelector结合条件注解实现"按需配置",体现Spring Boot"约定优于配置"的核心思想

正是这种精准的联动,使得Spring Boot能自动识别环境、加载适配的配置类,无需开发者手动编写大量配置。

五、Spring Boot 3.2.x中的优化

在Spring Boot 3.2.x版本中,对启动流程进行了以下优化:

5.1 延迟初始化优化

BeanDefinition的加载策略进行了调整,减少了启动时的内存占用。通过优化Bean定义的加载时机和方式,Spring Boot 3.2.x能够更高效地管理内存,特别是在大型应用中效果显著。

5.2 环境准备阶段重构

将环境变量的处理提前到上下文创建之前,提高了启动效率。这种重构使得环境配置的解析和验证能够更早完成,减少了后续阶段的等待时间。

5.3 其他性能优化

  • 启动性能监控 :引入了Startup类,提供更细粒度的启动性能监控
  • AOT支持增强:对AOT(Ahead-Of-Time)编译的支持更加完善,进一步提升启动速度
  • 资源加载优化:优化了资源文件的加载策略,减少了I/O操作
相关推荐
Klong.k39 分钟前
谈谈session、application存储对象
java·tomcat
阿杰AJie42 分钟前
Java 常见场景中需要使用 try 的示例集
java·后端
0***v77742 分钟前
JavaWeb项目打包、部署至Tomcat并启动的全程指南(图文详解)
java·tomcat
Lear42 分钟前
加密技术全面解析:从原理到实践
后端
回家路上绕了弯44 分钟前
多线程开发最佳实践:从安全到高效的进阶指南
分布式·后端
aiopencode1 小时前
混合开发应用安全方案,在多技术栈融合下构建可持续、可回滚的保护体系
后端
logocode_li1 小时前
面试 LoRA 被问懵?B 矩阵初始化为 0 的原因,大多数人拿目标来回答
人工智能·python·面试·职场和发展·矩阵
喵个咪1 小时前
初学者导引:在 Go-Kratos 中用 go-crud 实现 GORM CRUD 操作
后端·go
老华带你飞1 小时前
房屋租赁管理|基于springboot + vue房屋租赁管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·毕设