【问题标题】:Sorting CommandLineRunner execution排序 CommandLineRunner 执行
【发布时间】:2020-12-05 17:53:33
【问题描述】:

我有四个 CommandLineRunner 以特定顺序执行。其中两个被注释为@Component,另外两个被声明为 Bean。我使用@Order 注解来指定执行顺序,但在运行以下代码时发现了意外行为:

...
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }


    @Bean
    @Order(2)
    public CommandLineRunner upRunner(){
        return args -> log.info("2 - Running upRunner");
    }

    @Bean
    @Order(1)
    public CommandLineRunner downRunner(){
        return args -> log.info("1 - Running downRunner");
    }
}
...
@Component
@Order(4)
public class RightRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("4 - Running RightRunner");
    }
}
...
@Component
@Order(3)
public class LeftRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        log.info("3 - Running LeftRunner");
    }
}

执行不遵循@Order注解指定的顺序,见下面的日志:

[INFO ] Started App in 2.988 seconds (JVM running for 3.949)
[INFO ] 3 - Running LeftRunner
[INFO ] 4 - Running RightRunner
[INFO ] 2 - Running upRunner
[INFO ] 1 - Running downRunner

所以,看来:

  • 注释为@Component 的运行器按预期顺序执行,并且在其他运行器之前执行。
  • 声明为@Bean 的运行器按照它们在App 类中定义的顺序执行,而不考虑@Order 注释。

有什么我想念的东西来执行所需的命令吗? 有人可以澄清一下这种行为吗,我使用的是 spring-boot 版本 2.4.0?

Spring能够在注入时正确排序这些bean也很奇怪,只需在下面添加Bean:

...

    @Bean
    public Object runners(List<CommandLineRunner> runners) throws Exception {

        for(int i=0; i<runners.size(); i++){
            runners.get(i).run(null);
        }
        return new Object();
    }

日志显示注入的CommandLineRunner列表是按照@Order注解排序的:

[INFO ] 1 - Running downRunner
[INFO ] 2 - Running upRunner
[INFO ] 3 - Running LeftRunner
[INFO ] 4 - Running RightRunner
[INFO ] ...
[INFO ] Started App in 2.754 seconds (JVM running for 3.847)
[INFO ] 3 - Running LeftRunner
[INFO ] 4 - Running RightRunner
[INFO ] 2 - Running upRunner
[INFO ] 1 - Running downRunner

提前致谢,

安德烈亚

【问题讨论】:

  • 嘿安德里亚,你找到解释了吗?我在测试 CommandLineRunner 带注释的 bean 时遇到了同样的问题。
  • 嘿跳跃,还没有。

标签: java spring spring-boot


【解决方案1】:

我一直在调试,我看到在用于排序 CommandLineRunners 的 AnnotationAwareOrderComparator 中,当它到达方法 findOrderFromAnnotation 时,它使用 OrderUtils.getOrderFromAnnotations(element, annotations) 来获取指定的顺序。对于声明为@Bean 的bean,此方法返回null,而不是声明为@Component 的bean。

很抱歉,我无法更进一步,我也无法理解这种行为。

【讨论】:

  • 感谢 Hector 将我指向 OrderUtils,我正在尝试更好地调查这个问题,恕我直言,这可能是 Spring 核心中的一个错误。
【解决方案2】:

我也遇到了同样的问题。
由于我无法使用@Order 接口解决它,我实现了Ordered 接口来解决问题

【讨论】: