Spring Boot 钩子全集实战(十一):ApplicationRunner 详解
在上一篇中,我们深入剖析了 InitializingBean 这一 Bean 初始化阶段的核心接口,实现了依赖注入完成后的自定义初始化逻辑落地、解决了参数校验与缓存预热的场景需求。今天,我们将继续跟进 Spring Boot 启动生命周期,解析 ApplicationRunner 这一应用启动完成前的核心扩展接口。
一、ApplicationRunner 是什么?
ApplicationRunner是Spring Boot 框架提供的一个专属接口(位于 org.springframework.boot 包下),不属于 Spring 核心框架(Spring Core),是 Spring Boot 为应用启动流程提供的高级扩展点。
它的核心作用是让开发者实现该接口后,重写指定的业务方法,用于在 Spring 容器完全初始化完成、应用即将对外提供服务前,执行自定义的启动后业务逻辑。
二、ApplicationRunner 的执行时机
ApplicationRunner 接口方法的执行时机有严格的顺序要求,核心是在 Spring 容器完全就绪、Bean 全部初始化完成后,应用启动完成(如内嵌 Tomcat 启动)前执行,同时与 Spring Boot 另一个同类接口 CommandLineRunner (下一篇讲解)存在明确的执行先后顺序,具体完整执行链路如下:
- Spring 容器启动,完成所有 Bean 的创建、依赖注入、初始化(构造方法 → DI → @PostConstruct → InitializingBean#afterPropertiesSet ());
- 容器内所有 Bean 进入就绪状态,Spring 核心容器初始化完成;
- Spring Boot 检测容器中是否有实现了
ApplicationRunner接口的 Bean,若有则按指定顺序自动调用其重写的业务方法; - 若容器中同时存在
CommandLineRunner(下一篇讲解) 接口实现类,在ApplicationRunner执行完成后,执行CommandLineRunner接口方法; - 内嵌 Web 容器(如 Tomcat)启动(若为 Web 应用),应用完成全部启动流程,对外提供服务。
执行时机核心总结:
所有 Bean 初始化完成 → ApplicationRunner 接口方法 → CommandLineRunner 接口方法 → 内嵌容器启动 → 应用就绪对外服务
接口方法说明:
ApplicationRunner 接口仅定义了一个无返回值、接收 ApplicationArguments 类型参数的方法 run(),开发者只需让目标 Bean 实现该接口,并重写此方法即可写入启动后业务逻辑,通过 ApplicationArguments 可便捷获取命令行参数:
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
其中 ApplicationArguments 提供了丰富的参数操作方法,核心常用方法如下:
getOptionNames():获取所有带选项名的参数名称(如--server.port=8081中的server.port);getOptionValues(String name):根据选项名获取对应的参数值列表(支持多值);getSourceArgs():获取原始的命令行参数数组。
三、ApplicationRunner 的生产场景
在实际项目开发中,ApplicationRunner 专注于处理 “应用启动完成前、所有 Bean 已就绪” 的全局启动任务,以下是最常见的生产落地场景:
场景一:应用启动后初始化全局资源 / 执行一次性任务
项目启动完成后,需要执行一些一次性的全局初始化任务,如初始化全局配置缓存、注册中心服务注册校验、数据字典全量刷新等,此时可通过 ApplicationRunner 实现,且能依赖容器中已初始化完成的所有 Bean。
示例(初始化全局配置缓存):
@Component
@Slf4j
public class GlobalConfigRunner implements ApplicationRunner {
@Autowired
private GlobalConfigMapper globalConfigMapper;
// 全局静态配置缓存
public static Map<String, String> GLOBAL_CONFIG_CACHE = new ConcurrentHashMap<>();
// 应用启动完成前,执行全局配置缓存初始化
@Override
public void run(ApplicationArguments args) throws Exception {
// 查询所有全局配置
List<GlobalConfig> configList = globalConfigMapper.queryAllGlobalConfig();
for (GlobalConfig config : configList) {
GLOBAL_CONFIG_CACHE.put(config.getConfigKey(), config.getConfigValue());
}
log.info("全局配置缓存初始化完成,缓存条目数:{}" , GLOBAL_CONFIG_CACHE.size());
}
}
场景二:解析应用启动命令行参数,执行自定义逻辑
应用启动时通过命令行传入自定义参数(如 --app.env=prod --app.sync.data=true),需要在启动后解析这些参数并执行对应的业务逻辑,如根据环境参数加载不同配置、根据同步参数执行数据全量同步,ApplicationRunner 的 ApplicationArguments 提供了更便捷的参数解析能力。
示例(解析命令行参数执行数据同步):
@Component
@Slf4j
public class DataSyncRunner implements ApplicationRunner {
@Autowired
private DataSyncService dataSyncService;
@Override
public void run(ApplicationArguments args) throws Exception {
// 解析命令行中的 "app.sync.data" 选项参数
if (args.containsOption("app.sync.data")) {
List<String> syncValues = args.getOptionValues("app.sync.data");
if (syncValues != null && "true".equalsIgnoreCase(syncValues.get(0))) {
log.info("检测到启动参数:开启全量数据同步,开始执行同步任务...");
// 执行全量数据同步
dataSyncService.fullDataSync();
log.info("全量数据同步任务执行完成");
}
}
// 解析原始命令行参数
String[] sourceArgs = args.getSourceArgs();
log.info("应用启动原始命令行参数:{}" , Arrays.toString(sourceArgs));
}
}
扩展:指定多个 ApplicationRunner 的执行顺序
当容器中存在多个 ApplicationRunner 实现类时,可通过 @Order 注解或实现 Ordered 接口指定执行顺序,@Order 注解值越小,执行优先级越高:
// 优先级高,先执行
@Component
@Order(1)
@Slf4j
public class FirstRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("第一个 ApplicationRunner 执行(优先级1)");
}
}
// 优先级低,后执行
@Component
@Order(2)
@Slf4j
public class SecondRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("第二个 ApplicationRunner 执行(优先级2)");
}
}
四、总结
- 核心定位:
ApplicationRunner是 Spring Boot 专属接口,核心用于在所有 Bean 初始化完成、应用对外服务前执行全局一次性启动任务,由 Spring Boot 容器自动触发,支持便捷解析命令行参数; - 执行核心:严格遵循 “所有 Bean 初始化完成→ApplicationRunner(按 @Order 排序)→CommandLineRunner→内嵌容器启动→应用就绪” 的执行顺序;
- 场景价值:在全局配置缓存初始化、命令行参数解析等生产场景中广泛应用,能依托已就绪的全量 Bean 实现复杂启动任务,保证应用启动后的可用性和完整性。
📌 关注我,每天 5 分钟,带你从 Java 小白变身编程高手!
👉 点赞 + 关注 + 转发,让更多小伙伴一起进步!