将有序的 Bean 注入 Collection 不遵循定义的顺序

Injecting ordered Beans into a Collection does not honour the defined order

我有许多 bean 都实现了相同的类型,它们被标记为 @Order(x),其中 x 是 bean 的优先级。

通过将 bean 的集合作为参数传递给另一个 bean 来使用这些 bean,但是我们使用 SonarQube 来静态分析我们的代码,这建议您应该使用基础 class 除非您使用特定的功能child class.

@Bean
public SomeProcessor someProcessor(Collection<MyBean> beans) {
  return new SomeProcessor(beans);
}

如果我 @Inject 或将它们作为 List<> 传递,它们将保留 @Order 注释定义的顺序。

如果我 @Inject 或将它们作为 Collection<> 传递,它们将保留它们创建的顺序,忽略 @Order 注释。

这是 Spring 注入的预期行为(使用 Spring Boot 2.4.4)吗?或者这是我应该作为错误提出的问题吗?

下面的代码演示了这个问题(尽管在生产代码中我们没有将字符串创建为 Bean,因为那样会……不寻常):

@Inject
private List<String> stringList;

@Inject
private Collection<String> stringCollection;

@Bean
@Order(1)
public String stringBean1() {
  return "BEAN 1";
}

@Bean
@Order(3)
public String stringBean3() {
  return "BEAN 3";
}

@Bean
@Order(2)
public String stringBean2() {
  return "BEAN 2";
}

@PostConstruct
public void postConstruct() {
  log.error("{}", stringCollection);
  log.error("{}", stringList);
}

List按1、2、3顺序存储。 Collection 按顺序 1、3、2 存储,“忽略”@Order 注释。

我不知道这种行为是否记录在案,但它是可以接受和理解的。 Collection 没有说明底层实现,它可以是有序的或无序的。

文档是这样说的

A collection represents a group of objects, known as its elements. Some collections allow duplicate elements and others do not. Some are ordered and others unordered.

另一方面List

An ordered collection (also known as a sequence).

事实上,您正在使用 List class 的一项功能:它的顺序。我认为这里改为 Collection 是不正确的,因为你需要订购集合。

Spring 基于集合的排序最终在 4.0 版本中实现。 issue.

中记录了改进

您指出的问题在另一个 issue.

中以某种方式描述

但是正如那里所描述的,并且正如@jwillebrands 在 his/her 回答中指出的那样,Collection 可能会或可能不会被订购,而 Spring 只会保证订单在 lists and arrays:

Your target beans can implement the org.springframework.core.Ordered interface or use the @Order or standard @Priority annotation if you want items in the array or list to be sorted in a specific order. Otherwise, their order follows the registration order of the corresponding target bean definitions in the container.