CommandLineRunner 和 ApplicationRunner

CommandLineRunner 和 ApplicationRunner

背景:

项目启动之前,预先加载数据。比如,权限容器、特殊用户数据等。通常我们可以使用监听器、事件来操作。但是,springboot提供了一个简单的方式来实现此类需求,即,CommandLineRunner 和 ApplicationRunner。

话不多说,先看源码:

CommandLineRunner 和 ApplicationRunner 都是两个接口,继承了 Runner 接口。

CommandLineRunner

帮大家翻译一下:接口的实现必须包含在bean中,多个实现了CommandLineRunner的bean可以用@Order注解标识执行顺序。这里还说了,如果需要访问原始 ApplicationArguments 而不是字符串数组,可以使用ApplicationRunner。因为CommandLineRunner中run()方法的参数是字符串数组。

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 * <p>
 * If you need access to {@link ApplicationArguments} instead of the raw String array
 * consider using {@link ApplicationRunner}.
 *
 * @author Dave Syer
 * @since 1.0.0
 * @see ApplicationRunner
 */
@FunctionalInterface
public interface CommandLineRunner extends Runner {

	/**
	 * Callback used to run the bean.
	 * @param args incoming main method arguments
	 * @throws Exception on error
	 */
	void run(String... args) throws Exception;

}

ApplicationRunner

这里的注释与上面CommandLineRunner的注释差不多,就不介绍了。

package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * Interface used to indicate that a bean should <em>run</em> when it is contained within
 * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined
 * within the same application context and can be ordered using the {@link Ordered}
 * interface or {@link Order @Order} annotation.
 *
 * @author Phillip Webb
 * @since 1.3.0
 * @see CommandLineRunner
 */
@FunctionalInterface
public interface ApplicationRunner extends Runner {

	/**
	 * Callback used to run the bean.
	 * @param args incoming application arguments
	 * @throws Exception on error
	 */
	void run(ApplicationArguments args) throws Exception;

}

两者的使用:

CommandLineRunner

/**
 * @Author: wangrongyi
 * @Date: 2024/9/30 10:46
 * @Description:
 */
@Component
@Slf4j
public class CommandInitConfig implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        log.info("CommandInitConfig执行了");
        for (String arg : args) {
            log.info("arg = {}", arg);
        }
    }
}

项目启动之后,接着就会执行所有实现了CommandLineRunner接口的run方法,如果有多个,执行顺序跟bean的注入顺序相同。

如果有携带的参数,直接跟在启动命令后面

java -jar xxx.jar args1 args2 args3

image-20240930115230763

ApplicationRunner

/**
 * @Author: wangrongyi
 * @Date: 2024/9/30 11:13
 * @Description:
 */
@Component
public class ApplicationInitConfig implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("应用启动完成,正在执行初始化任务...");

        // 获取非选项参数
        String[] nonOptionArgs = args.getNonOptionArgs().toArray(new String[0]);
        for (String arg : nonOptionArgs) {
            System.out.println("非选项参数: " + arg);
        }

        // 获取选项参数
        String[] optionNames = args.getOptionNames().toArray(new String[0]);
        for (String optionName : optionNames) {
            System.out.println("选项名称: " + optionName);
            if (args.containsOption(optionName)) {
                System.out.println("包含选项: " + optionName);
                String[] optionValues = args.getOptionValues(optionName).toArray(new String[0]);
                for (String value : optionValues) {
                    System.out.println("选项值: " + value);
                }
            }
        }
    }
}

其中 ApplicationArguments 是 run()函数的参数,简单介绍一下这个接口:

ApplicationArguments 是 Spring Boot 提供的一个接口,用于处理命令行参数。它提供了一种更加结构化的方式来处理命令行参数,包括非选项参数(non-option arguments)和选项参数(option arguments)。该接口提供了几个获取参数的方法:

  • getNonOptionArgs():获取非选项参数列表。

    获取所有非选项参数,即不带 - 或 – 的参数

  • getOptionNames():获取所有选项名称。

    获取所有选项名称,即带 - 或 – 的参数。

  • containsOption(String name):判断是否包含指定选项。

    判断是否包含指定选项。

  • getOptionValues(String name):获取指定选项的所有值。

    获取指定选项的所有值。

ApplicationRunner 适合参数复杂的情况,打包后通过命令启动:

java -jar xxx.jar --option1=value1 --option2=value2 arg1 arg2

image-20240930135309912

总结:

两者都可以在程序启动后执行操作,且都支持获取启动参数并进行处理。

使用 ApplicationArguments:通过 ApplicationRunner 和 ApplicationArguments 来处理参数。
使用 CommandLineRunner:通过 run(String… args) 方法来处理参数。

那么实现了ApplicationRunner 和 CommandLineRunner接口的run方法是如何调用的呢?

下面我们跟随源码解读:

  1. 进入主程序的run方法。

image-20240930144745907

  1. 找到callRunners()方法

    image-20240930144827518

  2. 点进去之后会发现首选获取所有实现了Runner接口的bean,Runner接口只有两个子接口,所有也就是找到了所有实现了ApplicationRunner 和 CommandLineRunner接口的bean,然后遍历每个bean,调用callRunner方法执行。

  3. callRunner方法中区分了bean的类型,执行不同的代码。

    image-20240930145604165

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值