好的,下面是《【Java开发日记】说一说 SpringBoot 中 CommandLineRunner》的详细讲解,涵盖概念、作用、使用场景及示例代码,帮助你快速理解并掌握 CommandLineRunner 的实用方法。
☕ 【Java开发日记】说一说 SpringBoot 中 CommandLineRunner
目录
- CommandLineRunner 是什么?
- 作用与应用场景
- 如何使用 CommandLineRunner
- 多个 CommandLineRunner 的执行顺序
- 示例代码详解
- 与 ApplicationRunner 的区别
- 注意事项与最佳实践
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 区别
特性 | CommandLineRunner | ApplicationRunner |
---|---|---|
参数类型 | String... args | ApplicationArguments args |
作用 | 接收命令行参数字符串 | 提供更丰富的命令行参数解析方法 |
使用场景 | 简单启动逻辑执行 | 需要处理命令行参数更复杂时使用 |
7. 注意事项与最佳实践
- 不建议在
run
方法中执行耗时长、阻塞的操作,避免启动变慢 - 异常未捕获会导致应用启动失败
- 对于复杂逻辑,建议异步或延迟执行
- 合理使用多个
CommandLineRunner
并控制顺序
参考资料
- Spring Boot 官方文档:ApplicationRunner 和 CommandLineRunner
- 《Spring Boot 实战》——周志明
- Spring Framework 源码解析
明白了,下面给你一个完整示例工程,演示如何在 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
生效
发表回复