Springboot 启动过程及源码分析
Spring Boot 的启动过程是一个高度封装但逻辑清晰的流程,核心围绕 SpringApplication.run() 方法展开,涉及环境准备、上下文初始化、Bean 加载、Web 服务器启动等关键步骤。以下结合源码(基于 Spring Boot 2.7.x)详细拆解启动流程:
核心入口:SpringApplication.run()
所有启动逻辑的起点是主类的 main 方法,调用 SpringApplication.run(主类.class, args),该方法做两件事:
- 创建
SpringApplication实例(初始化启动器)。 - 调用实例的
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),用于在启动各阶段发布事件(如ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent等),串联整个启动流程。 - 调用
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→AnnotationConfigServletWebServerApplicationContextREACTIVE→AnnotationConfigReactiveWebServerApplicationContextNONE→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(),其中最关键的步骤包括:prepareRefresh():验证环境合法性,初始化上下文资源。obtainFreshBeanFactory():创建BeanFactory(默认DefaultListableBeanFactory),加载所有 Bean 定义。prepareBeanFactory(beanFactory):配置BeanFactory基础属性(如注册类加载器、Bean 表达式解析器)。postProcessBeanFactory(beanFactory):Spring Boot 扩展点,注册WebServerFactoryCustomizerBeanPostProcessor等组件,用于处理 Web 服务器配置。- 执行
BeanFactoryPostProcessor:解析@Configuration类中的@Bean方法,注册 Bean 定义。 - 注册
BeanPostProcessor:如AutowiredAnnotationBeanPostProcessor(处理@Autowired依赖注入)。 onRefresh():Spring Boot 核心扩展,启动嵌入式 Web 服务器(如 Tomcat):- 通过
ServletWebServerFactory创建 Web 服务器实例(如TomcatServletWebServerFactory.getWebServer())。 - 绑定端口(默认 8080),启动服务器。
- 通过
finishBeanFactoryInitialization(beanFactory):初始化所有非懒加载单例 Bean:- 实例化 Bean(调用构造方法)。
- 填充属性(依赖注入,如
@Autowired)。 - 执行初始化方法(
@PostConstruct、InitializingBean.afterPropertiesSet())。
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事件,通知监听器 “应用已就绪,可接收请求”,标志启动流程最终完成。
总结:启动流程核心节点
- 初始化
SpringApplication:推断应用类型、加载初始化器和监听器。 - 准备环境:加载配置、激活 profiles、发布环境准备事件。
- 创建上下文:根据应用类型实例化
ApplicationContext。 - 准备上下文:关联环境、注册 Bean 定义、执行初始化器。
- 刷新上下文:核心步骤,初始化 Bean、启动 Web 服务器。
- 启动后处理:执行 Runner 任务、发布就绪事件。
整个流程通过 事件驱动(ApplicationEvent + Listener)和 扩展点(Initializer、BeanPostProcessor 等)实现高度可定制,这也是 Spring Boot 灵活易用的核心原因。
