springboot⽣命周期全流程

生命周期流程,分为引导、启动、运行三个阶段,各阶段步骤及逻辑如下:
1. 引导阶段(蓝色背景)
- staring(启动):系统开始启动,进入初始状态。
- environmentPrepared(环境准备完成):完成运行环境的配置(如资源加载、环境变量初始化等),为启动阶段做准备。
2. 启动阶段(黄色背景)
包含四个依次执行的步骤,若任何一步失败,进入failed(启动失败)(红色区域,感知 6 个过程的错误):
- contextPrepared:
- IOC(控制反转)容器创建并准备完成,主程序未加载(如 Spring 容器初始化,Bean 定义加载但未实例化)。
- contextLoaded:
- IOC 容器加载(如 Bean 实例化),未刷新(容器状态未更新,可能未完成依赖注入)。
- started:
- IOC 容器刷新(完成依赖注入、初始化),但runner(任务执行器,如 Spring 的 ApplicationRunner)未调用。
- ready:
- runner 调用完成,系统启动完毕,进入可运行状态。
3. 运行阶段(绿色背景)
- context.isRunning ()(运行中):系统正常运行,处理业务逻辑,持续监听请求或执行任务。
流程逻辑:
- 引导→启动→运行:依次执行,引导阶段完成后进入启动阶段,启动阶段成功(ready)后进入运行阶段。
- 错误处理:启动阶段的任意步骤失败(如 IOC 初始化、runner 调用异常),立即触发
failed,终止启动流程。
关键概念:
- IOC(控制反转):容器管理对象的创建、依赖注入,简化开发(如 Spring 框架的核心机制)。
- runner:启动后执行的初始化任务(如加载配置、预热缓存),确保系统就绪。
应用场景:
典型于Spring Boot等框架的启动流程,通过生命周期回调(如ApplicationListener)监控各阶段状态,实现系统初始化、错误处理和运行时管理。
这张图清晰呈现了从启动到运行的全流程,各阶段职责明确,便于理解系统初始化逻辑和故障处理机制。
引导阶段的具体工作内容
引导阶段通常包含以下几个方面的工作:
- 环境变量检测与验证
-
- 检查Java版本、操作系统环境
- 验证必要的系统属性是否存在
- 检测配置文件路径是否可访问
- 配置源准备
-
- 加载系统属性、环境变量
- 解析命令行参数
- 读取配置文件(如application.properties/yml)
- 添加自定义配置源(示例中的
customProperties)
- 系统初始化
-
- 设置默认系统属性
- 注册应用程序监听器
- 初始化日志系统
- 准备事件发布器
- 条件初始化
-
- 根据环境变量或配置决定是否执行某些初始化步骤
- 预加载重要资源(如数据库驱动、缓存预热等)
实际应用中的例子
在Spring Boot应用中,引导阶段的具体实现可以在以下场景中看到:
SpringApplication.run()方法内部会先创建SpringApplication实例,然后调用prepareEnvironment()方法EnvironmentPostProcessor接口的实现类会在这个阶段被调用,用于修改环境配置ApplicationEnvironmentPreparedEvent事件会在环境准备完成后发布,允许应用程序添加自定义配置
引导阶段是系统启动的基础,确保运行环境满足应用程序的要求,为后续的IOC容器创建和Bean加载做准备。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 自定义引导过程
new SpringApplicationBuilder(DemoApplication.class)
.listeners(new CustomEnvironmentPreparedListener())
.build()
.run(args);
// 标准启动方式
// SpringApplication.run(DemoApplication.class, args);
}
// 环境准备阶段的监听器
static class CustomEnvironmentPreparedListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
// 获取配置环境
ConfigurableEnvironment environment = event.getEnvironment();
// 1. 环境变量检查
String javaVersion = System.getProperty("java.version");
System.out.println("检测到Java版本: " + javaVersion);
// 2. 自定义配置源
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("custom.environment", "development");
customProperties.put("app.start.time", System.currentTimeMillis());
// 添加到环境配置
MapPropertySource customSource = new MapPropertySource("customProperties", customProperties);
environment.getPropertySources().addFirst(customSource);
// 3. 配置文件加载检查
System.out.println("加载的配置文件: " + environment.getPropertySources());
// 4. 系统属性准备
if (!environment.containsProperty("system.initialized")) {
System.setProperty("system.initialized", "true");
}
// 5. 条件初始化(根据环境变量决定)
if ("true".equals(environment.getProperty("feature.enable.early-loading"))) {
preloadImportantResources();
}
}
// 预加载重要资源
private void preloadImportantResources() {
System.out.println("正在预加载重要资源...");
// 例如加载数据库驱动、初始化连接池等
}
}
}
引导阶段的实际场景使用
具体场景例子:Spring Boot 引导阶段加载外部配置中心(如 Nacos)的配置
场景描述:
在微服务项目中,应用的配置(如数据库连接、服务地址、日志级别等)通常存储在外部配置中心(如 Nacos、Consul)。引导阶段需要先从配置中心拉取最新配置,再将其整合到 Spring 环境中,确保后续启动过程(如 Bean 初始化、自动配置)使用正确的配置。
实现步骤:
- 创建配置中心客户端工具类(模拟从 Nacos 获取配置,实际需引入 Nacos SDK):
java
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import java.util.HashMap;
import java.util.Map;
public class ConfigCenterClient {
// 模拟从配置中心获取配置(实际需调用 Nacos API)
public static PropertySource<?> getConfig() {
Map<String, Object> configMap = new HashMap<>();
configMap.put("database.url", "jdbc:mysql://nacos-configured-host:3306/db");
configMap.put("server.port", "8081"); // 覆盖本地配置
return new MapPropertySource("configCenterProperties", configMap);
}
}
- 自定义引导阶段监听器(监听
ApplicationEnvironmentPreparedEvent,在环境准备时加载外部配置):
java
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
public class ConfigCenterBootstrapListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
// 1. 从配置中心获取配置
PropertySource<?> configCenterSource = ConfigCenterClient.getConfig();
// 2. 将外部配置添加到 Spring 环境(优先级高于本地配置文件)
environment.getPropertySources().addFirst(configCenterSource);
// 3. 验证配置(示例:检查数据库 URL 是否存在)
if (environment.getProperty("database.url") == null) {
throw new IllegalStateException("配置中心未返回数据库 URL,启动失败!");
}
System.out.println("引导阶段:加载配置中心配置完成,当前环境包含 " + environment.getPropertySources().size() + " 个配置源。");
}
}
- 注册监听器(两种方式,任选其一):
- 方式一:通过
spring.factories注册(在src/main/resources/META-INF/spring.factories中添加):properties
org.springframework.context.ApplicationListener=\ com.example.demo.ConfigCenterBootstrapListener - 方式二:在启动类中手动添加:
java
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(DemoApplication.class); app.addListeners(new ConfigCenterBootstrapListener()); // 手动添加监听器 app.run(args); } }
- 方式一:通过
流程说明:
-
引导阶段(蓝色背景):
staring(启动):SpringApplication 初始化,准备加载监听器和初始化器。environmentPrepared(环境准备完成):- 触发
ApplicationEnvironmentPreparedEvent,监听器ConfigCenterBootstrapListener执行。 - 从配置中心拉取配置,注入到
ConfigurableEnvironment(此时本地配置文件已加载,外部配置优先级更高,可覆盖本地值)。 - 验证配置合法性,确保后续启动步骤(如数据库连接初始化)有有效配置。
- 触发
-
后续启动阶段:
启动阶段(黄色背景)的contextPrepared、contextLoaded等步骤会使用引导阶段加载的完整配置(本地 + 配置中心),确保 Bean 初始化、自动配置(如DataSourceAutoConfiguration)使用正确的数据库 URL。
实际价值:
- 动态配置管理:无需修改本地配置文件,通过配置中心实时更新应用配置(如切换数据库地址、调整日志级别),提升运维灵活性。
- 环境隔离:开发、测试、生产环境的配置统一由配置中心管理,避免本地配置与线上环境不一致的问题。
- 故障提前检测:引导阶段验证配置(如数据库连接、服务地址),若配置缺失或错误,直接在启动初期报错,减少后续启动失败的排查成本。
扩展场景:
- 多环境配置加载:根据
spring.profiles.active(如dev、prod)从配置中心拉取对应环境的配置。 - 加密配置解密:引导阶段对配置中心的加密配置(如数据库密码)进行解密,确保敏感信息安全。
- 服务发现预热:在引导阶段调用服务发现组件(如 Eureka、Nacos 服务发现),提前获取依赖服务列表,加速启动阶段的服务调用准备。
通过上述例子,清晰展示了 Spring Boot 引导阶段在实际项目中加载外部配置的核心作用,是微服务架构中配置管理和启动流程优化的关键环节。
启动阶段(黄色背景)详解与实际项目应用
启动阶段是系统从环境准备到正式运行的关键过渡,主要围绕 Spring IOC 容器的初始化、Bean 加载与配置展开。下面结合实际项目场景,详细解释每个步骤的工作内容和应用价值:
1. contextPrepared:IOC 容器创建与准备
核心工作
- 创建
ApplicationContext(如AnnotationConfigApplicationContext)。 - 加载 Bean 定义(通过注解
@Component、XML 配置或 JavaConfig),但 不实例化 Bean。 - 注册 BeanFactoryPostProcessor 和 BeanPostProcessor(用于修改 Bean 定义或增强 Bean 实例)。
实际项目应用
- 扫描组件:Spring Boot 自动扫描
@SpringBootApplication所在包及其子包下的@Component、@Service、@Repository等注解类。 - 配置类解析:处理
@Configuration注解的配置类,解析@Bean方法定义的 Bean。 - 条件加载:根据
@Conditional注解(如@ConditionalOnClass、@ConditionalOnProperty)决定是否加载特定 Bean。
代码示例
java
// 启动类示例
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
// 自定义 BeanFactoryPostProcessor(修改 Bean 定义)
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 修改或注册 Bean 定义
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dataSource");
beanDefinition.getPropertyValues().add("maxActive", "100");
}
}
2. contextLoaded:IOC 容器加载 Bean 定义
核心工作
- 实例化 Bean(非懒加载 Bean),但 不触发依赖注入。
- 处理 Bean 生命周期回调(如
InitializingBean、@PostConstruct)。 - 解析 Bean 依赖关系,构建依赖图。
实际项目应用
- 自动装配:通过
@Autowired、@Resource或构造函数注入依赖 Bean。 - AOP 代理生成:为标注
@Transactional、@Async的 Bean 创建代理对象。 - 配置属性绑定:将配置文件(如
application.properties)的值注入到@ConfigurationProperties类。
代码示例
java
// 自动装配示例
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 依赖注入但未完成初始化
// Bean 初始化回调
@PostConstruct
public void init() {
System.out.println("UserService 初始化完成");
}
}
// 配置属性绑定
@ConfigurationProperties(prefix = "app")
@Component
public class AppConfig {
private String name;
private int port;
// getter/setter
}
3. started:IOC 容器刷新与依赖注入完成
核心工作
- 刷新容器:调用
AbstractApplicationContext.refresh(),完成 Bean 的依赖注入和初始化。 - 注册 事件监听器(如
ApplicationListener)。 - 触发
ContextRefreshedEvent事件。
实际项目应用
- 数据库连接池初始化:如 HikariCP、Druid 连接池创建初始连接。
- 消息队列消费者启动:如 RabbitMQ、Kafka 消费者订阅主题。
- 定时任务调度:启动
@Scheduled注解的定时任务。
代码示例
java
// 监听 ContextRefreshedEvent 事件
@Component
public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 容器刷新完成后执行,可获取完整初始化的 Bean
UserService userService = event.getApplicationContext().getBean(UserService.class);
System.out.println("容器刷新完成,UserService: " + userService);
}
}
4. ready:Runner 执行与系统就绪
核心工作
- 调用 ApplicationRunner 和 CommandLineRunner 接口的实现类,执行启动后任务。
- 触发
ApplicationReadyEvent事件。
实际项目应用
- 数据预热:加载缓存数据、初始化线程池。
- 健康检查:执行启动自检(如数据库连接测试、服务依赖检查)。
- 初始化任务:创建系统所需的目录、文件或数据库表。
代码示例
java
// 实现 CommandLineRunner 执行启动后任务
@Component
public class DataInitializer implements CommandLineRunner {
@Autowired
private UserService userService;
@Override
public void run(String... args) {
// 初始化数据
userService.initDefaultUsers();
System.out.println("默认用户初始化完成");
}
}
// 监听 ApplicationReadyEvent
@Component
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// 系统完全就绪,可对外提供服务
System.out.println("系统已就绪,当前时间:" + new Date());
}
}
实际项目中的启动流程优化
-
懒加载优化:
java
@Service @Lazy // 延迟加载,启动时不实例化 public class HeavyService { // 资源密集型服务 } -
条件加载:
java
@Service @ConditionalOnProperty(name = "feature.enabled", havingValue = "true") public class FeatureService { // 仅当配置项 feature.enabled=true 时加载 } -
异步初始化:
java
@Component public class AsyncInitializer { @Autowired private ApplicationContext context; @PostConstruct public void init() { CompletableFuture.runAsync(() -> { // 异步执行耗时操作 context.getBean(DataLoader.class).loadData(); }); } }
启动失败处理(红色区域)
若任何步骤失败(如 Bean 初始化异常、依赖服务不可用),系统会:
- 触发
ApplicationFailedEvent事件。 - 执行
FailureAnalyzers(如DataSourceBeanCreationFailureAnalyzer)分析错误原因。 - 打印详细错误堆栈,终止启动。
示例场景
- 数据库连接失败:
contextLoaded阶段初始化DataSource时抛出SQLException。 - 配置错误:
@Value注入的配置项不存在,导致IllegalArgumentException。
总结
启动阶段通过 分层初始化(Bean 定义 → 实例化 → 依赖注入 → 初始化回调)确保系统有序启动。实际项目中,合理利用这一机制可实现:
- 服务编排:控制 Bean 加载顺序(如
@DependsOn)。 - 启动性能优化:通过懒加载、异步初始化减少启动时间。
- 健壮性保障:在
ready阶段完成健康检查,避免服务带病上线。
这一流程在微服务、分布式系统中尤为重要,确保各组件按依赖关系正确初始化。
更多推荐




所有评论(0)