如何在 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);
}
我正在尝试使用一组特定类型的所有 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);
}