命令行运行程序的排序执行

3

我有四个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

谢谢您的提前预约,
安德烈

嗨,Andrea,你找到解释了吗?我在测试带有CommandLineRunner注释的bean时遇到了相同的问题。 - jumping_monkey
嘿,跳啊,你还没有跳得那么远。 - Devit.it
2个回答

1
我一直在调试,发现在AnnotationAwareOrderComparator中用于排序CommandLineRunners的方法findOrderFromAnnotation中,它使用OrderUtils.getOrderFromAnnotations(element, annotations)来获取指定的顺序。在您的情况下,对于声明为@Bean的bean而言,该方法返回null,但对于声明为@Component的bean则没有返回null。
很抱歉我无法进一步理解这种行为。

1
感谢 Hector 指出 OrderUtils,我正在尝试更好地调查这个问题,我认为这可能是 Spring 核心中的一个错误。 - Devit.it

1

我也遇到了相同的问题。
由于我无法通过 @Order 接口解决它,所以我实现了 Ordered 接口来解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接