Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ApplicationRunner与CommandLineRunner_Java_Spring Boot - Fatal编程技术网

Java ApplicationRunner与CommandLineRunner

Java ApplicationRunner与CommandLineRunner,java,spring-boot,Java,Spring Boot,我刚接触Spring boot,并阅读了有关ApplicationRunner和CommandLineRunner的信息。两者功能相同。当我同时实现两个接口时,总是先运行CommandLineRunner的方法,然后再运行ApplicationRunner的方法 任何人都可以提供帮助,为什么CommandLineRunner的方法优先于ApplicationRunner的方法。好吧,我认为在任何情况下都不需要同时实现这两个接口 这两种方法在实现时都表示应在应用程序启动时调用run方法 Appli

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


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

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

这两种方法在实现时都表示应在应用程序启动时调用
run
方法

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

使用
CommandLineRunner
您也可以访问它们,但作为原始字符串参数,因此您必须自己解析它们

您可以自己测试它:

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

@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));
    }
}
@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());
    }
}
使用
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));
    }
}
@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=xyz]
Arguments passed when bootstraping the app: [my-config]
使用
ApplicationRunner

@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));
    }
}
@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=xyz]
Arguments passed when bootstraping the app: [my-config]

正如您所看到的,它们提供了几乎相同的功能。我建议始终使用
ApplicationRunner
,因为这样您就不必自己解析参数了,因为Spring已经解析了参数,并且在
ApplicationArguments
对象中为您提供了参数。

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


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

这是通过查看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);
        }
    }
}
private void callrunner(ApplicationContext上下文、ApplicationArguments参数){
List runner=new ArrayList();
addAll(context.getBeansOfType(ApplicationRunner.class.values());
addAll(context.getBeansOfType(CommandLineRunner.class.values());
AnnotationAwareOrderComparator.sort(运行程序);
for(对象运行程序:新LinkedHashSet(运行程序)){
if(应用程序运行程序的运行程序实例){
callRunner((ApplicationRunner)runner,args);
}
if(CommandLineRunner的运行程序实例){
callRunner((CommandLineRunner)runner,args);
}
}
}
在我看来,您所做的是在同一个对象上实现两个runner接口。执行此操作时,上面的代码显示首先运行
ApplicationRunner
方法,然后运行
CommandLineRunner
方法。但你似乎说你看到了相反的行为。我实现了一个类,该类实现了两个运行程序,并且我看到这两个方法按照我期望的顺序执行

因此,您必须在两个不同的类中实现这些接口。在这种情况下,顺序由
annotationawaroredercomparator.sort
方法选择对两个运行程序类排序的方式决定,因为根据上述代码,此方法用于对所有运行程序列表进行排序,以确定调用它们的顺序

注释AwareOrderComparator的说明如下:

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

排序方法的描述如下:

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

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


好了。如果您需要更多的详细信息,您需要深入了解
AnnotationAwareOrderComparator
如何选择对两个类进行排序的详细信息。

您希望看到什么行为?一个怎么能不跑在另一个之前呢?奇怪的是,我只是想知道这种行为