当前位置: 首页 > news >正文

Springboot 启动过程及源码分析

Spring Boot 的启动过程是一个高度封装但逻辑清晰的流程,核心围绕 SpringApplication.run() 方法展开,涉及环境准备、上下文初始化、Bean 加载、Web 服务器启动等关键步骤。以下结合源码(基于 Spring Boot 2.7.x)详细拆解启动流程:

核心入口:SpringApplication.run()

所有启动逻辑的起点是主类的 main 方法,调用 SpringApplication.run(主类.class, args),该方法做两件事:

  1. 创建 SpringApplication 实例(初始化启动器)。
  2. 调用实例的 run(String... args) 方法(执行启动流程)。

源码简化如下:

java

运行

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);
}public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args); // 核心:创建实例并执行run
}

阶段一:SpringApplication 实例初始化(构造方法)

SpringApplication 实例化时会完成基础配置,为后续启动做准备。对应源码:

java

运行

public SpringApplication(Class<?>... primarySources) {this(null, primarySources);
}public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 步骤1:推断应用类型setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 步骤2:加载初始化器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 步骤3:加载监听器this.mainApplicationClass = deduceMainApplicationClass(); // 步骤4:推断主类
}
步骤 1:推断应用类型(WebApplicationType.deduceFromClasspath()
  • 功能:根据类路径中是否存在特定类,判断应用类型:
    • SERVLET:存在 Servlet 和 Tomcat 相关类(默认 Web 应用)。
    • REACTIVE:存在 Reactive 相关类(响应式 Web 应用)。
    • NONE:非 Web 应用。
  • 影响后续创建的 ApplicationContext 类型(如 ServletWebServerApplicationContext 或 ReactiveWebServerApplicationContext)。
步骤 2:加载初始化器(ApplicationContextInitializer
  • 功能:从 META-INF/spring.factories 中加载所有 ApplicationContextInitializer 实现类,用于在上下文刷新前自定义配置(如设置环境变量、激活配置文件)。
  • 关键方法:getSpringFactoriesInstances(ApplicationContextInitializer.class),通过 Spring 的 SpringFactoriesLoader 扫描类路径下的 spring.factories 文件。
步骤 3:加载监听器(ApplicationListener
  • 功能:同样从 META-INF/spring.factories 加载所有 ApplicationListener 实现类,用于监听启动过程中的事件(如环境准备完成、上下文刷新等),并执行回调逻辑(如日志打印、健康检查)。
步骤 4:推断主类(deduceMainApplicationClass()
  • 功能:通过栈追踪获取执行 main 方法的类,作为应用主类(后续组件扫描的起点)。

阶段二:执行启动流程(SpringApplication.run(args) 方法)

run 方法是启动的核心,源码简化如下(关键步骤已标注):

java

运行

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start(); // 启动计时器(记录启动耗时)ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty(); // 设置无头模式(用于服务器环境,避免图形化依赖)// 步骤1:获取启动监听器(SpringApplicationRunListener)SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(); // 发布启动开始事件(ApplicationStartingEvent)try {ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 解析命令行参数// 步骤2:准备环境(Environment)ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment); // 配置忽略BeanInfo(优化性能)// 步骤3:打印BannerBanner printedBanner = printBanner(environment);// 步骤4:创建ApplicationContextcontext = createApplicationContext();// 步骤5:准备异常报告器(处理启动异常)exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// 步骤6:准备上下文(关联环境、初始化器、Bean定义等)prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 步骤7:刷新上下文(核心!初始化Bean、启动Web服务器)refreshContext(context);// 步骤8:刷新后处理(空实现,留给子类扩展)afterRefresh(context, applicationArguments);stopWatch.stop(); // 停止计时器if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 步骤9:发布启动完成事件listeners.started(context);// 步骤10:执行Runner(启动后任务)callRunners(context, applicationArguments);} catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners); // 处理启动异常throw new IllegalStateException(ex);}try {// 步骤11:发布应用就绪事件listeners.running(context);} catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context; // 返回初始化完成的上下文
}
步骤 1:获取启动监听器(SpringApplicationRunListener
  • 功能:加载 META-INF/spring.factories 中的 SpringApplicationRunListener 实现类(默认 EventPublishingRunListener),用于在启动各阶段发布事件(如 ApplicationStartingEventApplicationEnvironmentPreparedEvent 等),串联整个启动流程。
  • 调用 listeners.starting() 发布 启动开始事件,通知所有 ApplicationListener 启动已开始。
步骤 2:准备环境(prepareEnvironment()
  • 功能:初始化并配置 Environment(环境对象,包含系统变量、环境变量、配置文件等),源码如下:

    java

    运行

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// 1. 创建环境(根据应用类型创建Servlet/Reactive/NONE环境)ConfigurableEnvironment environment = getOrCreateEnvironment();// 2. 配置环境(加载命令行参数、系统变量、配置文件等)configureEnvironment(environment, applicationArguments.getSourceArgs());// 3. 绑定环境到SpringApplication(用于后续配置)ConfigurationPropertySources.attach(environment);// 4. 发布环境准备完成事件(通知监听器修改环境)listeners.environmentPrepared(environment);// 5. 将环境绑定到应用(方便后续使用)bindToSpringApplication(environment);// 6. 非Web应用处理if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
    }
    
  • 关键操作:
    • 加载 application.yml/properties 等配置文件(通过 PropertySource 实现)。
    • 激活 spring.profiles.active 指定的配置文件。
    • 发布 ApplicationEnvironmentPreparedEvent 事件,允许监听器动态修改环境(如添加自定义属性)。
步骤 3:打印 Banner
  • 功能:根据 spring.main.banner-mode 配置,在控制台打印 Banner(默认是 Spring Boot 标志,可通过 src/main/resources/banner.txt 自定义)。
步骤 4:创建 ApplicationContext(上下文)
  • 功能:根据应用类型创建对应的 ApplicationContext(Spring 核心容器):
    • SERVLET → AnnotationConfigServletWebServerApplicationContext
    • REACTIVE → AnnotationConfigReactiveWebServerApplicationContext
    • NONE → AnnotationConfigApplicationContext
  • 源码逻辑:context = createApplicationContext(),通过反射实例化上下文对象。
步骤 5:准备异常报告器
  • 功能:加载 SpringBootExceptionReporter 实现类,用于在启动失败时生成异常报告(如打印自动配置报告)。
步骤 6:准备上下文(prepareContext()
  • 功能:在上下文刷新前完成初始化,关联环境、加载 Bean 定义等,源码核心逻辑:

    java

    运行

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 1. 将环境设置到上下文context.setEnvironment(environment);// 2. 配置上下文(如设置资源加载器、Bean名称生成器)postProcessApplicationContext(context);// 3. 执行初始化器(ApplicationContextInitializer)applyInitializers(context);// 4. 发布上下文准备事件(通知监听器)listeners.contextPrepared(context);// 5. 记录启动日志if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 6. 注册命令行参数Bean(供其他组件注入)ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}// 7. 禁止BeanFactory缓存BeanDefinition(避免重复加载)if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 8. 加载主类Bean定义(将@SpringBootApplication标注的主类注册为Bean)Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));// 9. 发布上下文初始化完成事件listeners.contextLoaded(context);
    }
    
  • 关键操作:
    • 执行 ApplicationContextInitializer 的 initialize() 方法(自定义上下文配置)。
    • 注册 springApplicationArguments 为单例 Bean(可通过 @Autowired 注入命令行参数)。
    • 加载主类及相关组件的 Bean 定义(通过 @ComponentScan 扫描)。
步骤 7:刷新上下文(refreshContext()
  • 功能:这是 Spring 容器的核心初始化步骤,复用 Spring Framework 的 AbstractApplicationContext.refresh() 方法,完成 Bean 实例化、依赖注入、Web 服务器启动等关键操作。

  • 源码核心调用:refresh(context) → AbstractApplicationContext.refresh(),其中最关键的步骤包括:

    1. prepareRefresh():验证环境合法性,初始化上下文资源。
    2. obtainFreshBeanFactory():创建 BeanFactory(默认 DefaultListableBeanFactory),加载所有 Bean 定义。
    3. prepareBeanFactory(beanFactory):配置 BeanFactory 基础属性(如注册类加载器、Bean 表达式解析器)。
    4. postProcessBeanFactory(beanFactory):Spring Boot 扩展点,注册 WebServerFactoryCustomizerBeanPostProcessor 等组件,用于处理 Web 服务器配置。
    5. 执行 BeanFactoryPostProcessor:解析 @Configuration 类中的 @Bean 方法,注册 Bean 定义。
    6. 注册 BeanPostProcessor:如 AutowiredAnnotationBeanPostProcessor(处理 @Autowired 依赖注入)。
    7. onRefresh():Spring Boot 核心扩展,启动嵌入式 Web 服务器(如 Tomcat):
      • 通过 ServletWebServerFactory 创建 Web 服务器实例(如 TomcatServletWebServerFactory.getWebServer())。
      • 绑定端口(默认 8080),启动服务器。
    8. finishBeanFactoryInitialization(beanFactory):初始化所有非懒加载单例 Bean:
      • 实例化 Bean(调用构造方法)。
      • 填充属性(依赖注入,如 @Autowired)。
      • 执行初始化方法(@PostConstructInitializingBean.afterPropertiesSet())。
    9. finishRefresh():完成上下文刷新,发布 ContextRefreshedEvent 事件。
步骤 8:刷新后处理(afterRefresh()
  • 功能:空实现,留给子类扩展(如自定义刷新后的逻辑)。
步骤 9:发布启动完成事件(listeners.started(context)
  • 功能:通过 SpringApplicationRunListener 发布 ApplicationStartedEvent 事件,通知监听器 “应用已启动(上下文刷新完成,Web 服务器已启动)”。
步骤 10:执行 Runner(callRunners()
  • 功能:调用所有 ApplicationRunner 和 CommandLineRunner 的 run() 方法(启动后任务),源码:

    java

    运行

    private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners); // 按@Order排序for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
    }
    
  • 作用:在所有 Bean 初始化完成后执行自定义逻辑(如数据加载、缓存预热)。
步骤 11:发布应用就绪事件(listeners.running(context)
  • 功能:发布 ApplicationReadyEvent 事件,通知监听器 “应用已就绪,可接收请求”,标志启动流程最终完成。

总结:启动流程核心节点

  1. 初始化 SpringApplication:推断应用类型、加载初始化器和监听器。
  2. 准备环境:加载配置、激活 profiles、发布环境准备事件。
  3. 创建上下文:根据应用类型实例化 ApplicationContext
  4. 准备上下文:关联环境、注册 Bean 定义、执行初始化器。
  5. 刷新上下文:核心步骤,初始化 Bean、启动 Web 服务器。
  6. 启动后处理:执行 Runner 任务、发布就绪事件。

整个流程通过 事件驱动ApplicationEvent + Listener)和 扩展点InitializerBeanPostProcessor 等)实现高度可定制,这也是 Spring Boot 灵活易用的核心原因。

http://www.dtcms.com/a/592732.html

相关文章:

  • STM32进行步进电机控制(PWM模式+翻转模式)
  • 信号系统常见的整体特性分类
  • PPT: Pre-trained Prompt Tuning - 预训练提示调优详解
  • 【RK3568】- 文件系统打包
  • 项目四:Dify智能开发与应用(零售企业基于Dify搭建会员智能运营平台)
  • 公司网站开发费计入什么科目迅当网络深圳外贸网站建设
  • 【C++11】右值引用+移动语义+完美转发
  • 商城系统的部署流程
  • 云朵课堂网站开发怎么收费装修公司口碑
  • python中numpy库学习笔记(2)
  • 【穿越Effective C++】条款16:成对使用new和delete时要采用相同形式——内存管理的精确匹配原则
  • 自己做的网站百度搜不到网站备案查询 工信部
  • 数据结构期中复习
  • TradingAgents-CN v1.0.0-preview 重磅发布!全新架构
  • 基于瑞萨 RA6M5 开发板的声源定位系统设计与实现
  • Vue 2 转 Vue 3, 差异不同点汇总, 快速上手vue3
  • 工业级环境传感器的网络通信与协议兼容性分析
  • 个人网站建设 免费下载一个公司备案两个网站
  • PR(1)11.10
  • 数据结构(19)
  • LWIP--以太网
  • 3分钟搞定,接口管理工具PostIn安装和配置
  • 【剑斩OFFER】算法的暴力美学——在排序数组中查找元素的第一个和最后一个位置
  • Agentic TASK01
  • 麒麟最新操作系统登录锁定配置
  • RLHF、DPO 算法
  • 网站排名优化课程网站建设公司华网天下官网
  • 营销型企业网站建设教案wordpress中调用文章内容
  • MySQL 错误 1046 (3D000) 是因为在执行 SQL 语句时 没有选择当前数据库
  • Jenkins Jobs 备份与恢复