游乐游手机版
首页/AI教程/文章详情

SpringBoot中SpringApplication启动过程详解

时间:2026-07-06 16:18
SpringBoot启动由SpringApplication run()触发,过程:创建实例、推断容器类型,加载初始化器和监听器,准备环境、加载配置,创建并初始化应用上下文,最后刷新容器完成Bean实例化与依赖注入。

Spring Boot 的启动过程,表面上看只是一个 SpringApplication.run() 的调用,但背后藏着一条高度结构化的执行链路。很多开发者只把它当黑盒用,遇到问题却不知道从哪下手。下面这张图概括了整体流程,而核心逻辑全写在 SpringApplication 这个类里——我们直接看源码,比看任何文档都实在。

SpringBoot中SpringApplication的启动过程

先看最经典的入口:一个 @SpringBootApplication 注解的类,配合 SpringApplication.run()。实际上 run 方法内部会先创建一个 SpringApplication 实例,再调用它的 run 方法。就是这么一层包装,把初始化、环境准备、容器创建、监听器触发等等全部串联起来。

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

public class SpringApplication {
    public static ConfigurableApplicationContext run(Class[] primarySources,
            String[] args) {
        return new SpringApplication(primarySources).run(args);
    }

    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        //资源加载器
        this.resourceLoader = resourceLoader;
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        //推断出要创建的容器类型
        this.webApplicationType = deduceWebApplicationType();
        //实例化所有的ApplicationContextInitializer
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        //实例化所有的ApplicationListener
        setListeners((Collection) getSpringFactoriesInstances(
                ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();

        //把SpringApplication的启动过程分成的很多阶段,每个阶段都有相应的事件抛出,
        //然后会有一些监听器监听整个启动过程。
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

            //准备环境,并将配置文件中的配置加载到environment中
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);

            //创建applicationContext
            context = createApplicationContext();

            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);

            //准备context
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);

            //创建相关的对象,并注册到容器中
            refreshContext(context);
            afterRefresh(context, applicationArguments);

            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }

        return context;
    }

    private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        //创建一个可配置的environment对象,所有的配置都会放在这个对象中
        ConfigurableEnvironment environment = getOrCreateEnvironment();

        //默认配置设置到environment,配置profile
        configureEnvironment(environment, applicationArguments.getSourceArgs());

        //事件监听,其中ConfigFileApplicationListener将配置文件里面的配置都加载到environment中
        listeners.environmentPrepared(environment);
        bindToSpringApplication(environment);

        if (this.webApplicationType == WebApplicationType.NONE) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertToStandardEnvironmentIfNecessary(environment);
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

    protected void configureEnvironment(ConfigurableEnvironment environment,
            String[] args) {
        //把设置的默认的配置和命令行配置加到environment中
        configurePropertySources(environment, args);
        //配置profile到environment中
        configureProfiles(environment, args);
    }

    private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        postProcessApplicationContext(context);

        //调用ApplicationContextInitializer的initialize()方法
        applyInitializers(context);

        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }

        // Add boot specific singleton beans
        context.getBeanFactory().registerSingleton("springApplicationArguments",
                applicationArguments);
        if (printedBanner != null) {
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }

        // Load the sources
        Set sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");

        //注册BeanDefinition到BeanDefinitionRegistry中
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }
}


仔细看这段代码会发现,Spring Boot 把启动过程拆成了多个清晰的阶段:从容器类型推断、初始化器和监听器的加载,到环境准备、上下文创建、Bean 定义注册,每一步都有对应的事件触发和监听器回调。这种设计保证了高度可扩展性——你甚至可以通过 ApplicationContextInitializerApplicationListener 在启动过程中插入自定义逻辑。

需要特别留意的是 prepareEnvironment 阶段,它通过 ConfigFileApplicationListenerapplication.properties(或 yml)中的配置加载到 Environment 对象中。这意味着所有外部配置都集中在启动早期完成,后续的 Bean 创建可以直接引用。另一个关键点是 refreshContext,它调用了 Spring 容器的核心刷新方法,所有单例 Bean 的实例化、依赖注入、AOP 袋里都在这里完成。

理解了这些步骤,以后再遇到 Spring Boot 启动异常,就能顺着事件顺序定位问题——到底是环境加载失败,还是某个 Initializer 抛了异常,又或者是 Bean 定义冲突。这才是掌握框架的正确姿势。

来源:https://developer.aliyun.com/article/704982
上一篇AIGC安全治理的三道防线:输入输出及运营闭环 下一篇上机考试操作题自动评分系统技术原理与实现难点
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
阿里云Qoder CN灵码AI助手免费版及credits计费指南
AI教程 · 2026-07-06

阿里云Qoder CN灵码AI助手免费版及credits计费指南

阿里云QoderCN(原通义灵码)是一款AI智能编码助手,提供IDE插件、独立IDE等形态,覆盖编码及日常办公场景。产品分个人社区版(免费)、个人专业版、企业标准版和企业VPC版,采用Credits计费模式,支持多种AI模型。

基于大模型的城市文旅知识图谱构建与内容分发
AI教程 · 2026-07-06

基于大模型的城市文旅知识图谱构建与内容分发

大模型构建城市知识图谱时优先采信权威信源。贵港西江传媒联合《度假旅游》杂志,通过本地采编、期刊发布、阿里云多平台分发模式,产出产业文旅等结构化内容,提升AI知识库收录权重,为城市品牌长效传播提供可复制路径。

贵州文旅AIGEO内容运营本地媒体落地实践
AI教程 · 2026-07-06

贵州文旅AIGEO内容运营本地媒体落地实践

针对贵州文旅行业在阿里云平台的内容运营痛点,总结合规发文规则,包括弱化营销、避免引流信息与极限词。以《度假旅游杂志》在贵阳设立本地化运营站点为例,为黔域文旅商家产出合规原创内容,提升AI平台收录权重。同时指出商家常踩的审核红线,强调以干货分享获取自然流量。

阿里内部禁用Claude Code OpenCode成替代方案
AI教程 · 2026-07-06

阿里内部禁用Claude Code OpenCode成替代方案

ClaudeCode对国内用户定向封禁,网传阿里内部已全面禁用。OpenCode作为开源替代,支持接入多种AI模型,通过CCSwitch或手动配置可无缝迁移原有MCP与AgentSkill,规避账号风险。

年实测Homebrew安装配置国内源多种安装方式一篇搞定
AI教程 · 2026-07-06

年实测Homebrew安装配置国内源多种安装方式一篇搞定

Homebrew是macOS上流行的包管理工具,提供pkg安装包、脚本安装和Git克隆等多种安装方式。国内用户推荐使用镜像脚本安装并配置中科大或清华大学镜像源以加速下载。常用命令包括brewinstall安装工具、brewinstall--cask安装图形应用、brewupdate更新及brewdoctor诊断环境。