Spring Boot多CommandLineRunner执行顺序与执行完成依赖保证问题
核心结论
Spring Boot 2.3.2版本中,CommandLineRunner默认就是按@Order注解的优先级从小到大串行同步执行的,你最初加@Order的写法已经可以满足「@Order(2)的Runner在@Order(1)的Runner全部处理完成后再执行」的需求,不需要额外改造。
Spring Boot调用CommandLineRunner的逻辑是:在应用启动完成后,收集所有CommandLineRunner类型的Bean,按@Order值排序后,在主线程中依次调用每个Bean的run方法,前一个run方法完全执行结束后才会调用下一个。
逐个解答你的疑问
1. @DependsOn注解能不能实现需求?
不能。@DependsOn仅控制Bean的实例化、初始化顺序,只能保证MyFailureHandlerA的Bean实例创建、初始化完成后,才会创建MyFailureHandlerB的Bean实例,但Bean初始化完成不代表run方法执行完成,完全无法控制run方法的执行顺序,不要用这个方案。
2. 单例Bean标记状态的方案是否推荐?
不推荐。
该方案可以实现需求,但属于冗余实现,本身原生框架已经支持顺序执行,额外加状态控制还要处理等待逻辑、中断异常,反而容易引入死锁、阻塞启动失败等问题,没有必要。
3. 合并到同一个CommandLineRunner依次调用的方案是否合理?
非常合理,完全可以保证操作按顺序执行。
Java的方法调用本身就是串行执行的,some_io_calls_q()执行完成后才会执行some_io_calls_b(),如果这两个业务逻辑关联性较高,合并到同一个Runner中是更简洁、更易维护的实现方式。
注意事项
如果你的run方法内部包含异步逻辑(比如主动开线程、提交线程池执行任务没有同步等待返回),不管用哪种方案都需要保证run方法退出前,异步任务已经全部执行完成,否则还是会出现执行顺序不符合预期的问题。
内容的提问来源于stack exchange,提问作者Kumar Ashutosh

