ApplicationRunner applicationRunner 是什么?

概念介绍

ApplicationRunner 是 Spring Boot 中的一个接口,用于在 Spring Boot 应用程序启动后执行特定的任务或逻辑。它允许开发者在应用程序完全启动后执行一些初始化操作,例如加载数据、调用外部服务或执行其他业务逻辑。

如何使用 ApplicationRunner

要使用 ApplicationRunner,需要创建一个实现了 ApplicationRunner 接口的类,并实现其 run() 方法。在该方法中编写希望在应用程序启动后执行的代码逻辑。示例代码如下:

import org.springframework.boot.*;
import org.springframework.stereotype.*;

@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner started with arguments: " + args.getOptionNames());
        // 在这里编写你的初始化逻辑
    }
}

也可以直接在启动类Application.class文件中直接引入:

/**
 * 创建线程池任务
 */
@Bean
public ApplicationRunner applicationRunner(ExecutorService threadPoolExecutor01) {
    System.out.println("threadPoolExecutor01:");
    System.out.println(threadPoolExecutor01);
    return args -> {
        while (true) {
            // 创建一个随机时间生成器
            Random random = new Random();
            // 随机启动时间,用于模拟任务启动延迟
            int randomInitialTime = random.nextInt(10) + 1; // 随机生成1-10之间的整数
            // 随机任务时间,用于模拟任务执行时间
            int randomTaskTime = random.nextInt(10) + 1; // 随机生成1-10之间的整数
            // 提交任务到线程池
            threadPoolExecutor01.submit(() -> {
                try {
                    // 模拟任务启动延迟
                    Thread.sleep(randomInitialTime * 1000);
                    System.out.println("线程池任务在 " + randomInitialTime + " 秒后启动。");
                    // 模拟任务执行时间
                    Thread.sleep(randomTaskTime * 1000);
                    System.out.println("线程池任务执行了 " + randomInitialTime + " 秒。");
                } catch (Exception exception) {
                    // 中断当前线程
                    Thread.currentThread().interrupt();
                }
            });
        }
    };
}

ApplicationRunner 的特点和用途

执行时机:

ApplicationRunner 的 run() 方法在 Spring Boot 应用程序启动完成后立即执行。这意味着它可以用来执行需要在整个应用程序上下文初始化后进行的操作。

参数传递:

run() 方法的参数 ApplicationArguments 提供了启动参数的访问。通过 ApplicationArguments 可以获取命令行参数、选项和非选项参数等信息,从而更灵活地配置和初始化应用程序。

<think> 我们正在讨论ApplicationRunner和CommandLineRunner的区别。根据引用[1]和[4],这两个接口都用于在Spring Boot应用程序启动后执行特定的代码逻辑,但它们在处理命令行参数的方式上有所不同。 引用[4]明确指出:CommandLineRunner接收的参数是最原始的参数(字符串数组),而ApplicationRunner的参数是ApplicationArguments,它是对原始参数做了进一步封装。 此外,引用[1]提到:如果你需要对命令行参数进行更细致的操作和解析,选择ApplicationRunner;如果需求简单,则CommandLineRunner足矣。 因此,我们可以从以下几个方面来阐述两者的区别: 1. 参数类型:CommandLineRunner的run方法接收的是字符串数组(String[] args),而ApplicationRunner的run方法接收的是ApplicationArguments对象。 2. 参数处理:ApplicationArguments提供了更方便的方法来访问参数,例如可以区分选项参数(带--前缀)和非选项参数。 3. 执行顺序:根据引用[2]和[5],如果有多个Runner,可以通过@Order注解或实现Ordered接口来指定顺序,但这两个接口本身的执行顺序没有先后之分(即同Order值的情况下,执行顺序不确定?)。不过引用[5]提到:“SpringApplication的run()方法完成之前回调”,所以它们都是在启动后执行,执行时机相同。 下面我们详细说明: 一、参数类型与处理 - CommandLineRunner: ```java @Component public class MyRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { // args是一个字符串数组,包含所有的命令行参数(包括选项和非选项) // 例如:--name=spring 会作为字符串"--name=spring"传入 } } ``` - ApplicationRunner: ```java @Component public class MyRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { // 通过ApplicationArguments可以更方便地获取参数 // 例如:获取选项参数(带--前缀的参数) List<String> nameArgs = args.getOptionValues("name"); // 返回值为List<String>,因为可能有多个同名选项 // 获取非选项参数(不带--前缀的参数) List<String> nonOptionArgs = args.getNonOptionArgs(); // 还可以获取原始的参数数组 String[] sourceArgs = args.getSourceArgs(); } } ``` 二、使用场景 根据引用[1]和[4]: - 当需要简单处理命令行参数时,使用CommandLineRunner即可。 - 当需要对命令行参数进行更复杂的处理,特别是需要区分选项参数和非选项参数时,使用ApplicationRunner更加方便。 三、执行顺序 根据引用[5]: - 多个CommandLineRunner或ApplicationRunner可以通过@Order注解或实现Ordered接口来指定执行顺序。 - 注意:这两个接口的执行顺序是混合在一起的,即Spring Boot不会先执行所有CommandLineRunner再执行ApplicationRunner,而是根据Order值统一排序。 四、示例对比 假设启动命令:`java -jar app.jar --name=Spring boot hello world` 在CommandLineRunner中: ```java public void run(String... args) { // args数组内容为:["--name=Spring", "boot", "hello", "world"] } ``` 在ApplicationRunner中: ```java public void run(ApplicationArguments args) { // 选项参数:args.getOptionNames() 包含"name" // args.getOptionValues("name") 返回["Spring"] // 非选项参数:args.getNonOptionArgs() 返回["boot","hello","world"] } ``` 总结: | 特性 | CommandLineRunner | ApplicationRunner | |----------------|---------------------------------------|---------------------------------------------| | **参数类型** | `String... args` | `ApplicationArguments args` | | **参数处理** | 原始字符串数组 | 封装后的对象,提供便捷方法 | | **适用场景** | 简单参数处理 | 需要解析选项参数和非选项参数 | | **执行顺序** | 与ApplicationRunner一起按Order排序 | 与CommandLineRunner一起按Order排序 | 因此,选择哪个接口取决于对命令行参数的处理需求。 根据引用[1][3][4],我们可以给出建议:如果不需要对参数进行特别的解析,两者都可以;如果需要更复杂的参数解析,推荐ApplicationRunner。 最后,引用[5]说明它们都是在容器启动成功之后,SpringApplication的run()方法完成之前回调,所以执行时机相同。 相关问题: 1. 如何在多个Runner中控制执行顺序? 2. 除了ApplicationRunner和CommandLineRunner,还有哪些Spring Boot启动扩展点? 3. 如何从Runner中访问Spring容器中的Bean? 4. 在Runner中抛出异常会对应用启动产生什么影响? </think> ### ApplicationRunner与CommandLineRunner区别详解 #### 一、核心差异对比 | **特性** | **ApplicationRunner** | **CommandLineRunner** | |------------------|-----------------------------------------------|-----------------------------------------| | **参数类型** | `ApplicationArguments`(封装对象) | `String...`(原始字符串数组) | | **参数处理能力** | 提供结构化访问方法(如选项参数、非选项参数) | 仅原始字符串数组 | | **复杂参数支持** | 支持多值参数<br>(如`--key=value1,value2`) | 需要手动解析多值参数 | | **推荐场景** | 需要精细处理命令行参数时 | 简单任务且无需复杂参数解析时 | #### 二、参数处理差异详解 1. **ApplicationRunner参数处理** ```java @Override public void run(ApplicationArguments args) { // 获取选项参数(带--前缀) List<String> names = args.getOptionValues("name"); // 获取非选项参数 List<String> nonOptionArgs = args.getNonOptionArgs(); // 检查参数存在性 boolean debug = args.containsOption("debug"); } ``` 输入命令:`java -jar app.jar --name=Alice --name=Bob input.txt` - `getOptionValues("name")` → `["Alice", "Bob"]` - `getNonOptionArgs()` → `["input.txt"]`[^4] 2. **CommandLineRunner参数处理** ```java @Override public void run(String... args) { // 需手动解析原始参数 for (String arg : args) { if (arg.startsWith("--name=")) { String name = arg.substring(7); } } } ``` 相同输入命令: - `args`数组 → `["--name=Alice", "--name=Bob", "input.txt"]`[^4] #### 三、执行机制对比 | **特性** | 两者共同点 | 两者区别 | |------------------|-------------------------------------------|---------------------------------------| | **执行时机** | 均在Spring上下文就绪后,应用完全启动前执行 | 无本质差异 | | **执行顺序** | 可通过`@Order`注解指定优先级 | 同优先级的执行顺序不确定 | | **Bean访问** | 均可注入其他Spring Bean | 无差异 | | **异常处理** | 抛出异常会导致应用启动失败 | 相同行为 | #### 四、选型建议 ✅ **优先选择ApplicationRunner当**: - 需要处理多值参数(如`--files=1.txt,2.txt`) - 需区分选项参数和非选项参数 - 需要参数存在性检查(如`containsOption()`) - 涉及复杂参数逻辑(如参数分组、验证) ✅ **优先选择CommandLineRunner当**: - 只需简单遍历原始参数 - 无参数解析需求(如单纯执行初始化任务) - 兼容旧版Spring Boot(1.x版本)代码 > **典型场景示例**: > ```java > // 需要解析参数 → ApplicationRunner > @Override > public void run(ApplicationArguments args) { > if(args.containsOption("init-db")) { > databaseService.initialize(); > } > } > > // 无需参数 → CommandLineRunner > @Override > public void run(String... args) { > cacheManager.preload(); // 无参数依赖 > } > ``` #### 五、混合使用建议 通过`@Order`控制多个Runner的执行顺序: ```java @Order(1) @Component public class FirstRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { // 先执行参数解析 } } @Order(2) @Component public class SecondRunner implements CommandLineRunner { @Override public void run(String... args) { // 再执行无参数任务 } } ``` > **最佳实践**:当应用同时需要两种Runner时,推荐将参数解析逻辑集中在`ApplicationRunner`中,其他Runner通过共享服务组件获取解析结果[^1][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值