CommandLineRunner 是什么?

Spring Boot 里,CommandLineRunner 是一个非常常用、但又容易被低估的启动钩子接口


一、CommandLineRunner 是什么?

CommandLineRunnerSpring Boot 提供的一个接口

java 复制代码
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

👉 只做一件事:

在 Spring Boot 应用启动完成后,执行一段代码


二、什么时候执行?(生命周期位置)

Spring Boot 启动顺序(简化版):

复制代码
1. SpringApplication.run()
2. 创建 ApplicationContext
3. 扫描 Bean / 注入依赖
4. 执行 @PostConstruct
5. 执行 CommandLineRunner / ApplicationRunner
6. 启动完成(应用对外可用)

📌 关键点:

  • 所有 Bean 已经初始化完成
  • @Autowired 可以正常用
  • 适合做 启动后初始化逻辑

三、最基本用法

方式一:实现接口(最常见)

java 复制代码
@Component
public class InitRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Spring Boot 启动完成");
    }
}

启动后控制台输出:

复制代码
Spring Boot 启动完成

方式二:@Bean 方式(更灵活)

java 复制代码
@Bean
public CommandLineRunner init() {
    return args -> {
        System.out.println("执行初始化逻辑");
    };
}

适合 配置类中集中管理启动逻辑


四、args 是什么?

args 就是 启动 JVM 时的命令行参数

bash 复制代码
java -jar app.jar --env=prod --debug=true

run 里:

java 复制代码
@Override
public void run(String... args) {
    for (String arg : args) {
        System.out.println(arg);
    }
}

输出:

复制代码
--env=prod
--debug=true

📌 注意:

  • Spring 的 application.properties 参数也会被解析,但这里拿到的是原始命令行

五、多个 CommandLineRunner 的执行顺序

如果你有多个 Runner:

java 复制代码
@Component
@Order(1)
public class FirstRunner implements CommandLineRunner {
    public void run(String... args) {
        System.out.println("First");
    }
}
java 复制代码
@Component
@Order(2)
public class SecondRunner implements CommandLineRunner {
    public void run(String... args) {
        System.out.println("Second");
    }
}

执行顺序:

复制代码
First
Second

📌 规则:

  • 数字 越小越先执行
  • 也可以实现 Ordered 接口

六、和 ApplicationRunner 的区别(面试常问)

对比项 CommandLineRunner ApplicationRunner
参数 String... args ApplicationArguments
参数解析 需要自己拆 已解析(key-value)
易用性 简单 更强
使用频率 ⭐⭐⭐⭐⭐ ⭐⭐⭐

ApplicationRunner 示例:

java 复制代码
@Component
public class AppRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        args.getOptionNames().forEach(System.out::println);
    }
}

七、常见使用场景(非常重要)

1️⃣ 初始化缓存(Redis / 本地缓存)

java 复制代码
@Component
public class CacheInitRunner implements CommandLineRunner {

    @Autowired
    private UserService userService;

    @Override
    public void run(String... args) {
        userService.loadAllUsersToCache();
    }
}

✔ 广告 / 游戏后台非常常见

✔ 你之前提到 Redis、广告初始化,这个用法很典型


2️⃣ 启动时校验配置

java 复制代码
@Override
public void run(String... args) {
    if (StringUtils.isEmpty(apiKey)) {
        throw new RuntimeException("API_KEY 未配置");
    }
}

📌 失败就让服务启动失败


3️⃣ 初始化定时任务 / 监听器

java 复制代码
@Override
public void run(String... args) {
    taskManager.start();
}

4️⃣ 数据迁移 / 表结构检查(轻量级)

java 复制代码
@Override
public void run(String... args) {
    migrateService.checkAndFix();
}

5️⃣ 游戏 / 广告 SDK 初始化

你做广告变现,这种非常常见:

java 复制代码
@Override
public void run(String... args) {
    AdConfig.init();
    SdkManager.load();
}

八、和 @PostConstruct 的区别(重点)

对比 @PostConstruct CommandLineRunner
执行时机 单个 Bean 初始化后 全部 Bean 初始化完成
是否能注入其他 Bean 有风险 安全
执行次数 每个 Bean 一次 全局一次
适合做 Bean 内部初始化 系统级初始化

📌 经验法则:

  • Bean 自己的事 → @PostConstruct
  • 系统启动的事 → CommandLineRunner

九、注意事项(踩坑点)

❌ 1. 不要写阻塞死循环

java 复制代码
@Override
public void run(String... args) {
    while (true) {} // ❌ 服务卡死
}

✔ 如果要长任务,新开线程


❌ 2. 不要写超慢逻辑

  • 拖慢服务启动
  • Kubernetes / 云环境容易被判定启动失败

✔ 推荐做法

java 复制代码
@Override
public void run(String... args) {
    CompletableFuture.runAsync(() -> initHeavyTask());
}

十、一句话总结

CommandLineRunner 是 Spring Boot 提供的启动完成回调接口,用于在容器完全初始化后执行系统级初始化逻辑,常用于缓存预热、配置校验、任务启动等场景。

相关推荐
abcnull3 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡3 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan4 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054734 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路4 小时前
C++23概述
java·c++·c++23
专注API从业者5 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠5 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
keep one's resolveY6 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端
天空属于哈夫克36 小时前
企业微信API常见的错误和解决方案
java·数据库·企业微信