CommandLineRunner是最推荐的Spring Boot启动初始化方式,它确保所有Bean、依赖、数据库连接池、Redis、MQ等均就绪后才执行逻辑;只需实现接口、加@Component注解、重写run(String[] args)方法,并可用@Order控制多任务顺序。

Spring Boot 项目启动时加载初始化数据,CommandLineRunner 是最推荐、最稳妥的标准方式。它确保所有 Bean 已创建完毕、依赖注入完成、数据库连接池、Redis 客户端、MQ 等外部组件都已就绪,才执行你的逻辑。
怎么写一个基础的 CommandLineRunner
只需三步:
- 定义一个类,实现
CommandLineRunner接口 - 加上
@Component注解,让 Spring 扫描到它 - 重写
run(String[] args)方法,把初始化代码放进去
示例:
(注意:参数是String[],不是单个 String)
@Component
public class DataInitRunner implements CommandLineRunner {
@Autowired
private UserService userService;
@Override
public void run(String[] args) throws Exception {
// 此时 userService 已完全可用,事务、AOP 都已生效
if (userService.countAdminUsers() == 0) {
userService.createDefaultAdmin();
}
}
}
多个 Runner 怎么控制执行顺序
当有多个初始化任务(比如先建字典表、再刷缓存、最后启动监听器),必须明确先后关系。Spring Boot 提供两种等效方式:
- 用
@Order(数字)注解:数字越小,优先级越高(如@Order(1)最先执行) - 让类实现
Ordered接口,重写getOrder()方法返回整数值
例如:
@Component @Order(1)
public class DictDataRunner implements CommandLineRunner { ... }
@Component @Order(2)
public class CachePreloadRunner implements CommandLineRunner { ... }
@Component @Order(3)
public class MqConsumerStarter implements CommandLineRunner { ... }
什么时候该用 CommandLineRunner,而不是其他方式
它特别适合以下场景:
- 检查并插入缺失的基础数据(管理员账号、默认角色、系统配置)
- 从 DB 加载字典表到 Redis 或本地缓存
- 启动前探活下游服务(调一次健康接口,失败则抛异常中止启动)
- 打印关键启动信息(版本号、配置中心地址、当前 profile)便于运维排查
不建议用于:
- 耗时过长的任务(如全量同步百万数据)——会阻塞主线程,导致应用“假死”超时被杀;应改用异步线程池 + 启动后延迟触发
- 需要在 Bean 初始化阶段就运行的逻辑(比如修改某个 Bean 的内部状态)——此时应考虑
@PostConstruct或构造器注入
CommandLineRunner 和 ApplicationRunner 有什么区别
两者执行时机完全一样,都是容器刷新完成后、服务对外提供请求前。区别只在参数封装方式:
-
CommandLineRunner.run(String[] args):拿到原始命令行字符串数组,适合简单判断(如args[0].equals("init")) -
ApplicationRunner.run(ApplicationArguments args):提供结构化访问能力,可区分选项参数(--debug)、非选项参数(prod)、获取参数值等,更健壮
如果项目需支持灵活的启动参数(如 java -jar app.jar --mode=full --tenant=abc),优先选 ApplicationRunner。


















