[英]Inject a merged list of beans within @Configuration
First, let me introduce a few simple classes and interface to be able to describe my problem. 首先,让我介绍一些简单的类和接口来描述我的问题。
interface Basic { void foo(); }
interface Extended extends Basic { void bar(); }
class BasicService {
@Inject
List<Basic> basics;
void execute() {
basics.forEach(Basic::foo);
}
}
class ExtendedService {
@Inject
List<Extended> extendeds;
void execute() {
extendeds.forEach(Extended::bar);
}
}
@Configuration
class MyConfiguration {
// Assume, that Basic1 and Basic2 are implementations of Basic and
// Extended1 is an implementation of Extended
@Bean
public Basic basic1() {
return new Basic1();
}
@Bean
public Basic basic2() {
return new Basic2();
}
@Bean
public List<Extended> extendeds() {
return Arrays.asList(new Extended1("0"), new Extended1("1"), new Extended1("2"));
}
@Bean
public BasicService basicService() {
return new BasicService();
}
@Bean
public ExtendedService extendedService() {
return new ExtendedService();
}
}
I have two services that act on different level of abstraction. 我有两个服务,它们作用于不同的抽象级别。 My problem is that I'm failing to find a way how I can inject all beans that implement the
Basic
interface in my BasicService
. 我的问题是我无法找到一种方法来注入所有在
BasicService
中实现Basic
接口的BasicService
。 With the current implementation it only injects all Extended
implementations, because I have a factory bean method that has a return type of List
in its method signature. 对于当前的实现,它仅注入所有
Extended
实现,因为我有一个工厂bean方法,其方法签名中具有List
的返回类型。
I can not change the bean configuration in a way that all Extended
beans have their own factory methods, because in my real code the number of Extended
implementations is dynamically computed on runtime... 我无法以所有
Extended
bean都有自己的工厂方法的方式更改bean配置,因为在我的真实代码中, Extended
实现的数量是在运行时动态计算的...
Is there a way I can configure Spring, so that it merges all beans with Basic
and List<Basic>
together in 1 big list that I can use in my BasicService
? 有没有一种方法可以配置Spring,以便将所有具有
Basic
和List<Basic>
bean合并到一个可以在BasicService
使用的大列表中?
I'm not sure whether there is a way to solve this implicitly, since Spring tries to find the best match, which the List bean seems to be (have you tried generics, eg, List<? extends Basic>
?). 我不确定是否有一种隐式解决此问题的方法,因为Spring试图找到List Bean似乎是的最佳匹配项(您是否尝试过泛型,例如
List<? extends Basic>
?)。
But you could do it programmatically, by getting the bean definitions from the ApplicationContext : 但是您可以通过从ApplicationContext获取Bean定义来以编程方式进行操作:
public BasicService(@Inject ApplicationContext ctx) {
Map<String, ? extends Basic> basicMap = ctx.getBeansOfType(Basic.class);
Map<String, Collection<? extends Basic>> basicCollectionMap = ctx.getBeansofType(ResolvableType.forClassWithGenerics(Collection.class, Basic.class));
// Now merge
Collection<? extends Basic> basics = basicMap.values();
basicCollectionMap.values().stream().map(l -> basics.addAll(l));
}
I just typed this here, so I hope there aren't any obvious errors. 我只是在这里输入,因此希望没有明显的错误。
I solved the problem by adding generic bean definitions for the Extended
implementations. 我通过为
Extended
实现添加通用bean定义解决了这个问题。 This can be done by adding a BeanDefinitionRegistryPostProcessor
implementation to the @Configuration
class as follows: 这可以通过将
BeanDefinitionRegistryPostProcessor
实现添加到@Configuration
类来完成,如下所示:
@Configuration
class MyConfiguration {
@Bean
public static ExtendedBeanFactory extendedBeanFactory() {
return new ExtendedBeanFactory();
}
}
class ExtendedBeanFactory implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
for (int i = 0; i < 3; i++) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Extended1.class);
ConstructorArgumentValues args = new ConstructorArgumentValues();
args.addGenericArgumentValue(Integer.toString(i));
beanDefinition.setConstructorArgumentValues(args);
registry.registerBeanDefinition("extended_" + i, beanDefinition);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// noop
}
}
This has the advantage, that consumer classes can simply inject a list of Basic
or a list of Extended
as the code from the question does. 这样做的好处是,使用者类可以像问题代码一样简单地插入
Basic
列表或Extended
列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.