ApplicationRunner VS CommandLineRunner

问题描述 投票:0回答:4

我是 Spring boot 新手,阅读了有关 ApplicationRunnerCommandLineRunner 的信息。两者的功能相同。当我同时实现两个接口时,总是先运行 CommandLineRunner's 方法,然后运行 ApplicationRunner's 方法。

任何人都可以提供帮助,为什么 CommandLineRunner 的 方法优先于 ApplicationRunner 的 方法。

java spring-boot
4个回答
5
投票

这是您问题的真正答案,通过查看 Spring 代码获得。 所有运行程序都在启动结束时由主线程运行,通过此方法:

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

在我看来,您正在做的事情是在同一个对象上实现两个运行器接口。 当您这样做时,上面的代码显示首先运行

ApplicationRunner
方法,然后运行
CommandLineRunner
方法。 但你似乎说你看到了相反的行为。 我实现了一个实现两个运行器的类,并且我看到这两个方法按照我预期的上述代码顺序执行。

因此您必须在两个不同的类中实现这些接口。在这种情况下,顺序取决于

AnnotationAwareOrderComparator.sort
方法如何选择对两个运行器类进行排序,因为根据上面的代码,使用此方法对所有运行器的列表进行排序以确定它们的调用顺序.

AnnotationAwareOrderComparator
的描述是:

AnnotationAwareOrderComparator 是 OrderComparator 的扩展,它支持 Spring 的 Ordered 接口以及 @Order 和 @Priority 注解,Ordered 实例提供的顺序值会覆盖静态定义的注解值(如果有)。

排序方法的描述是:

使用默认的 AnnotationAwareOrderComparator 对给定列表进行排序。

显然,如果您想强制运行器执行特定的顺序,您可以使用 @order 或 @Priority 注释来实现。

所以你已经得到它了。 如果您需要比这更详细的信息,您需要深入了解

AnnotationAwareOrderComparator
如何选择如何订购两个课程的详细信息。


4
投票

嗯,我认为在任何情况下都不需要同时实现这两个接口。

两者在实现时都表明应在应用程序启动时调用

run
方法。

ApplicationRunner
CommandLineRunner
之间的区别在于,在
ApplicationRunner
上,我们有一个
run
的实例,而不是传递给
ApplicationArguments
方法的原始字符串参数,这样您就可以访问在正在初始化应用程序。

使用

CommandLineRunner
你也可以访问它们,但是作为原始字符串参数,所以你必须自己解析它们。

你可以自己测试一下:

使用参数

--my-config=xyz
运行应用程序将在实现
ApplicationRunner
CommandLineRunner
时提供以下结果:

使用

CommandLineRunner

@Component
public class CLIRunner implements CommandLineRunner {

    @Override
    public void run(String...args) throws Exception {
        System.out.println("Arguments passed when bootstraping the app: " + Arrays.asList(args));
    }
}

输出:

Arguments passed when bootstraping the app: [--my-config=xyz]

使用

ApplicationRunner

@Component
public class AppRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("Arguments passed when bootstraping the app: " + args.getOptionNames());
    }
}

输出:

Arguments passed when bootstraping the app: [my-config]

正如您所见,它们都提供几乎相同的功能。我建议始终使用

ApplicationRunner
,因为那样你就不必自己解析参数,因为 Spring 已经这样做了,并在
ApplicationArguments
对象中提供了它。


0
投票

CommandLineRunner 和 ApplicationRunner 之间的区别在于 CommandLineRunner 的 run() 方法接受 String 数组作为参数,而 ApplicationRunner 的 run() 方法接受 spring ApplicationArguments 作为参数。

要按顺序执行它们,可以使用 spring @Order 注解或 Ordered 接口。


0
投票

另一种方法是直接与Bean一起使用,如下所示:

@Bean
ApplicationRunner appRunner() {
    return args -> {
        // Any code functionalities can be done here as such spawning threads.
        logger.info("Args: {}", args.getNonOptionArgs());
    };
}

这也适用于创建 CommandLineRunner 接口。

@Bean
CommandLineRunner commandLineRunner() {
    return args -> {
        // Any code functionalities can be done here as such spawning threads.
        logger.info("Args: {}", args);
    };
}

这样你就不需要重写这些接口并实现 run 方法。 Spring Boot 将在初始化应用程序时处理它。

© www.soinside.com 2019 - 2024. All rights reserved.