如何在 Spring 中实现基于注释的集合合并?

How can I achieve annotation-based collection merging in Spring?

我正在尝试使用一组特定类型的所有 bean 来初始化一个 Spring 组件(实际上,我可以迭代的任何东西)。

Spring 核心文档讨论了 collection merging,但仅在基于注释的配置的上下文中。

假设我有以下配置

@Configuration
public class MyConfig {
    @Bean
    public SomeInterface single() {
        return new SomeInterface() {};
    }

    @Bean
    public Set<SomeInterface> multi() {
        return Collections.singleton(
            new SomeInterface() {}
        );
    }
}

其中接口定义为

public interface SomeInterface {}

我希望此组件获得两个 bean 的聚合 - 一些包含两个匿名的集合 类。

@Component
public class MyComponent {
    public MyComponent(Set<SomeInterface> allInterfaces) {
        System.out.println(allInterfaces.size()); // expecting 2, prints 1
    }
}

我明白为什么 Spring 会得到这样的结果;它看到这个方法需要一个 Set<SomeInterface> 并且 MyConfig::multi 是一个 Set<SomeInterface> 类型的 bean,所以它自动装配那个。

如果我将签名更改为 Collection<SomeInterface>,它会使用 MyConfig::single 自动装配。再一次,我明白了原因:没有任何东西完全匹配,但是有 SomeInterface 类型的 bean(在这种情况下,只有一个)所以它构造了它们的临时集合并使用它自动装配。很好,但不是我想要的。

我希望解决方案是可扩展的,这样如果添加另一个 bean,依赖组件就不需要更改。我试过使用两个参数,每个参数都有一个 @Qualifier,这有效但不可扩展。

我怎样才能让它工作?

正如您已经提到的,MyConfig::multi 是一个 Set<SomeInterface> 类型的 bean,因此自动装配 Collection<Set<SomeInterface>> 将为您提供所有这些集合。以下应该有效

public MyComponent(Collection<SomeInterface> beans,
                   Collection<Set<SomeInterface>> beanSets) {
    // merge both params here
}

如果您需要在多个地方实现所有实现,那么定义另一个包含合并集合的 bean 并自动装配该 bean 可能是有意义的:

static class SomeInterfaceCollection {
    final Set<SomeInterface> implementations;

    SomeInterfaceCollection(Set<SomeInterface> implementations) {
        this.implementations = implementations;
    }
}

@Bean
public SomeInterfaceCollection collect(Collection<SomeInterface> beans,
        Collection<Collection<SomeInterface>> beanCollections) {
    final HashSet<SomeInterface> merged = ...
    return new SomeInterfaceCollection(merged);
}