好的,下面是《【Java开发日记】说一说 SpringBoot 中 CommandLineRunner》的详细讲解,涵盖概念、作用、使用场景及示例代码,帮助你快速理解并掌握 CommandLineRunner 的实用方法。


☕ 【Java开发日记】说一说 SpringBoot 中 CommandLineRunner


目录

  1. CommandLineRunner 是什么?
  2. 作用与应用场景
  3. 如何使用 CommandLineRunner
  4. 多个 CommandLineRunner 的执行顺序
  5. 示例代码详解
  6. 与 ApplicationRunner 的区别
  7. 注意事项与最佳实践

1. CommandLineRunner 是什么?

CommandLineRunner 是 Spring Boot 提供的一个接口,位于 org.springframework.boot 包下。
它包含一个 run(String... args) 方法,允许你在 Spring Boot 应用启动完成后执行一些自定义逻辑。


2. 作用与应用场景

  • 应用启动时执行初始化任务,例如加载缓存、预热数据、启动后台任务等
  • 自动执行一次性的配置或检查
  • 调试或测试用的简单代码执行

3. 如何使用 CommandLineRunner

只需实现该接口,并重写 run 方法。实现类可以是组件、配置类或者 Spring Bean。

例子:

@Component
public class MyStartupRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("Spring Boot 启动完成,执行 CommandLineRunner");
        // 初始化操作
    }
}

Spring Boot 启动完后,容器会自动调用所有 CommandLineRunner 实现类的 run 方法。


4. 多个 CommandLineRunner 的执行顺序

当项目中有多个实现时,可以通过实现 org.springframework.core.Ordered 接口或使用 @Order 注解来指定执行顺序。

@Component
@Order(1)
public class FirstRunner implements CommandLineRunner { ... }

@Component
@Order(2)
public class SecondRunner implements CommandLineRunner { ... }

数字越小,优先级越高,越先执行。


5. 示例代码详解

@Component
public class DataInitializer implements CommandLineRunner {

    private final UserRepository userRepository;

    public DataInitializer(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public void run(String... args) throws Exception {
        // 判断数据库是否有数据
        if(userRepository.count() == 0){
            userRepository.save(new User("admin", "admin123"));
            System.out.println("初始化管理员用户完成");
        }
    }
}

作用:启动时检测数据库,自动创建初始用户。


6. CommandLineRunner 与 ApplicationRunner 区别

特性CommandLineRunnerApplicationRunner
参数类型String... argsApplicationArguments args
作用接收命令行参数字符串提供更丰富的命令行参数解析方法
使用场景简单启动逻辑执行需要处理命令行参数更复杂时使用

7. 注意事项与最佳实践

  • 不建议在 run 方法中执行耗时长、阻塞的操作,避免启动变慢
  • 异常未捕获会导致应用启动失败
  • 对于复杂逻辑,建议异步或延迟执行
  • 合理使用多个 CommandLineRunner 并控制顺序

参考资料

明白了,下面给你一个完整示例工程,演示如何在 Spring Boot 中使用多个 CommandLineRunner,包括执行顺序控制、异常处理及异步执行,帮你快速上手实战。


【Spring Boot CommandLineRunner 完整示例工程】


1. 项目结构

src/main/java/com/example/demo/
│
├── DemoApplication.java       // 主启动类
├── runner/
│   ├── FirstRunner.java       // 第一个 CommandLineRunner
│   ├── SecondRunner.java      // 第二个 CommandLineRunner(异步执行)
│   └── ExceptionRunner.java   // 演示异常捕获
└── config/
    └── AsyncConfig.java       // 异步线程池配置

2. 主启动类 DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3. 第一个同步执行 Runner FirstRunner.java

package com.example.demo.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)  // 优先执行
public class FirstRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("FirstRunner 执行,优先级最高");
    }
}

4. 异步执行 Runner SecondRunner.java

package com.example.demo.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
@Order(2)
public class SecondRunner implements CommandLineRunner {

    @Override
    @Async  // 标注异步
    public void run(String... args) throws InterruptedException {
        System.out.println("SecondRunner 开始异步执行");
        Thread.sleep(3000);
        System.out.println("SecondRunner 异步执行完成");
    }
}

5. 异常处理 Runner ExceptionRunner.java

package com.example.demo.runner;

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(3)
public class ExceptionRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        try {
            System.out.println("ExceptionRunner 运行,开始模拟异常");
            throw new RuntimeException("测试异常");
        } catch (Exception e) {
            System.err.println("ExceptionRunner 捕获异常: " + e.getMessage());
        }
    }
}

6. 异步配置 AsyncConfig.java

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
    // 使用默认线程池,若需要自定义线程池可自行配置
}

7. 运行效果(控制台输出示例)

FirstRunner 执行,优先级最高
ExceptionRunner 运行,开始模拟异常
ExceptionRunner 捕获异常: 测试异常
SecondRunner 开始异步执行
... 3秒后 ...
SecondRunner 异步执行完成

8. 说明

  • @Order 注解控制执行顺序,数字越小越先执行
  • @Async 让 SecondRunner 异步执行,避免阻塞启动线程
  • 异常必须捕获,否则会导致 Spring Boot 启动失败
  • 异步方法需配合 @EnableAsync 生效