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

SpringBoot 启动入口深度解析:main方法执行全流程

一、main方法的启动本质

Spring Boot应用的启动入口是标准的Java main方法,但它的特殊之处在于:

@SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {//.....}

关键点

  1. JVM加载主类时不会处理类上的注解(如@SpringBootApplication
  2. 所有注解处理都由Spring容器在初始化阶段完成
  3. main方法本质是Spring容器的启动触发器

二、main方法执行瞬间的关键动作

当JVM执行main方法时,在SpringApplication.run()调用瞬间发生以下关键操作:

1. SpringApplication实例化

// SpringApplication.run()内部实现
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);
}public ConfigurableApplicationContext run(String... args) {// 记录应用启动时间戳和初始化指标收集器Startup startup = Startup.create();// 如果配置了关闭钩子(默认true),则注册JVM关闭时清理资源的钩子if (this.properties.isRegisterShutdownHook()) {SpringApplication.shutdownHook.enableShutdownHookAddition();}// 创建引导上下文(BootstrapContext),用于早期初始化组件DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 应用上下文ConfigurableApplicationContext context = null;// 强制设置awt.headless模式(确保无图形界面的服务器环境正常工作)configureHeadlessProperty();// 获取并初始化SpringApplicationRunListener集合(从spring.factories加载)SpringApplicationRunListeners listeners = getRunListeners(args);// 发布ApplicationStartingEvent事件(最早的生命周期事件)listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 解析命令行参数(封装为ApplicationArguments对象)ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备环境配置(加载properties/yml,合并命令行参数,发布ApplicationEnvironmentPreparedEvent事件)ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 打印Banner(控制台图标,可通过spring.banner.*配置)Banner printedBanner = printBanner(environment);// 根据应用类型创建对应的ApplicationContext(Servlet/Reactive/普通)context = createApplicationContext();// 设置应用启动指标收集器context.setApplicationStartup(this.applicationStartup);// 准备应用上下文(配置Bean工厂,注册单例,发布ApplicationContextInitializedEvent事件)prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// ★核心:刷新上下文(加载配置类,初始化所有Bean,启动嵌入式服务器)refreshContext(context);// 上下文刷新后的扩展点(默认空实现,可被子类覆盖)afterRefresh(context, applicationArguments);// 记录启动完成时间点startup.started();// 如果配置了启动日志(默认true),打印应用启动信息(版本、端口等)if (this.properties.isLogStartupInfo()) {new StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup);}// 发布ApplicationStartedEvent事件(上下文已刷新但未调用Runner)listeners.started(context, startup.timeTakenToStarted());// 执行ApplicationRunner和CommandLineRunner实现类callRunners(context, applicationArguments);}catch (Throwable ex) {// 处理启动失败:发布ApplicationFailedEvent事件并抛出异常throw handleRunFailure(context, ex, listeners);}try {// 检查上下文是否在运行状态(正常流程应处于运行中)if (context.isRunning()) {// 发布ApplicationReadyEvent事件(应用完全就绪,可接收请求)listeners.ready(context, startup.ready());}}catch (Throwable ex) {// 处理就绪事件阶段的异常throw handleRunFailure(context, ex, null);}// 返回已初始化的应用上下文return context;
}

执行步骤

  1. 主类App.class作为primarySources保存
  2. 推断应用类型(Servlet/Reactive/None)
  3. 加载META-INF/spring.factories中的扩展点:
    • BootstrapRegistryInitializer
    • ApplicationContextInitializer
    • ApplicationListener
  4. 记录主应用类(含@SpringBootApplication的类)

2. 主类注解的识别时机

核心结论:主类上的@SpringBootApplication注解在 容器刷新阶段(refresh() 才被真正解析,由ConfigurationClassPostProcessor触发:

  1. @ComponentScan → 扫描当前包下的@Component@Service等组件。
  2. @EnableAutoConfiguration → 通过AutoConfigurationImportSelector加载AutoConfiguration.imports中的配置类。

在这里插入图片描述

三、@SpringBootApplication注解处理流程

主类注解的真正处理发生在容器刷新阶段,由ConfigurationClassPostProcessor完成:

1、配置类识别

  • invokeBeanFactoryPostProcessors()阶段,扫描所有@Configuration类(主类因@SpringBootApplication@SpringBootConfiguration@Configuration被识别)

2、注解元数据解析

解析@SpringBootApplication组合注解中的@ComponentScan@EnableAutoConfiguration

//org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {//*****略*****// 处理@ComponentScanSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class,MergedAnnotation::isDirectlyPresent);//*****略*****for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}// Process any @Import annotations// 处理@Import(包含@EnableAutoConfiguration)processImports(configClass, sourceClass, getImports(sourceClass), filter, true);//*****略*****
}

3、三大核心注解处理

注解组件处理方式作用
@SpringBootConfiguration作为@Configuration处理标记主类为配置类
@ComponentScan触发包扫描扫描当前包及子包的@Component@Service等组件
@EnableAutoConfiguration通过AutoConfigurationImportSelector加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

4、自动配置加载

// AutoConfigurationImportSelector逻辑
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 从spring.factories加载自动配置类List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).getCandidates();return configurations;
}

四、main方法启动时的完整执行序列

阶段关键操作是否处理主类注解
JVM加载主类1. 加载静态字段 2. 执行静态初始化块
main方法执行1. 创建SpringApplication实例 2. 存储主类引用
SpringApplication.run()1. 准备环境 2. 创建ApplicationContext 3. 注册主类Bean定义
refreshContext()1. invokeBeanFactoryPostProcessors() 2. 触发ConfigurationClassPostProcessor
配置类处理1. 解析@SpringBootApplication 2. 执行包扫描 3. 加载自动配置类

五、核心处理组件协作图

在这里插入图片描述

六、关键设计解析

  1. 延迟注解处理
    • Spring Boot 3.5.0使用延迟注解解析策略
    • 主类在refresh()阶段才被真正处理
    • 优点:允许环境准备完成后进行条件化配置
  2. 条件注解处理
// 自动配置类的条件检查
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@AutoConfiguration(after = ServletWebServerFactoryAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
public class DispatcherServletAutoConfiguration {// 仅当类路径存在Servlet和DispatcherServlet时生效
}
  1. 配置类解析顺序
1. 主配置类(@SpringBootApplication)
2. 自动配置类(AutoConfiguration.imports)
3. @ComponentScan扫描到的配置类
4. @Import引入的配置类

七、总结

核心结论:main 方法只是 Spring Boot 启动的"点火器",真正的注解解析发生在容器刷新阶段,由 Spring 的 ConfigurationClassPostProcessor引擎完成,与 Java 原生的注解处理机制完全分离。

http://www.xdnf.cn/news/14890.html

相关文章:

  • 颠覆传统加密:微算法科技创新LSQb算法,提升量子图像处理速度
  • 【debug日记】解决 Conda 激活命令未正确配置的问题
  • Redis学习笔记——黑马点评 附近商铺到UV统计 完结
  • Tomcat 安装使用教程
  • 机电一体化论文写作实战指南:从创新设计到工程验证的完整路径
  • 学习使用dotnet-dump工具分析.net内存转储文件(3)
  • OpenCV学习3
  • Java面试宝典:基础三
  • 学习React官方文档(描述UI)
  • 《弦论视角下前端架构:解构、重构与无限延伸的可能》
  • mapstate
  • OSPF(开放最短路径优先)
  • 【NLP 实战】蒙古语情感分析:从 CNN 架构设计到模型训练的全流程解析(内附项目源码及模型成果)
  • 认知智能平台搭载LLM+RAG,重构行业洞察与决策支持体系!
  • 实战四:基于PyTorch实现猫狗分类的web应用【2/3】
  • PCB设计实践(三十七)PCB机械孔设计全解析:作用原理与设计规范指南
  • MyBatis实战指南(八)MyBatis日志
  • ai数据分析黄金
  • ideal2025安装教程
  • Elasticsearch 集群升级实战指引—7.x 升级到 8.x
  • 流量低、获客越来越难?创客匠人让知识变现不走弯路
  • HarmonyOS NEXT仓颉开发语言实战案例:健身App
  • redis延时双删,为什么第一次删除
  • 什么是 Solidity 以太坊上主流合约语言?
  • 【大语言模型入门】—— 浅析LLM基座—Transformer原理
  • Hive SQL 快速入门指南
  • Linux基本命令篇 —— less命令
  • 华为云Flexus+DeepSeek征文|利用华为云一键部署的Dify平台构建高效智能电商客服系统实战
  • 【论文阅读笔记】知网SCI——基于主成分分析的空间外差干涉数据校正研究
  • java进阶