我正在尝试控制 spring 中的依赖注入,以便@Autowired
注释只注入一部分 bean,但我还没有遇到提供这种行为的解决方案。
想象一下,有许多特定类型的 bean,但您只想在各种上下文中使用某些 bean。@Autowired
注释支持 bean 集合,但它似乎不支持对可以注入的各种 bean (AFAIK) 应用限制。
@Autowired
Set<Foo> beansForContextA;
@Autowired
Set<Foo> beansForContextB;
上面的代码会将同一组 bean 注入beansForContextA
和beansForContextB
中。我想要一种方法来区分哪些豆子被注入到它各自的属性中。弹簧中内置的东西是否支持此用例?
请考虑以下伪代码,以更清楚地说明期望:
@Configuration
public class Config {
@Bean(tags = {"A"})
Foo bean1() {
...
}
@Bean(tags = {"B"})
Foo bean2() {
...
}
@Bean(tags = {"A", "B"})
Foo bean3() {
...
}
}
@Configuration
public class Impl {
@Autowired(tags = {"A"})
Set<Foo> beansForContextA;
@Autowired(tags = {"B"})
Set<Foo> beansForContextB;
public void execute() {
for (Foo foo : someCondition ? beansForContextA : beansForContextB) {
...
}
}
}
在这里,我希望beansForContextA
拥有bean1
和bean3
,beansForContextB
拥有bean2
和bean3
.这可以通过扩展@Autowired
和@Bean
注释来支持"标签"来实现,但我很好奇是否有一个已经成熟的解决方案,或者我必须发明自己的解决方案?
或者,这甚至是一个好主意吗?也许还有另一种我还没有遇到过的方法。
@Qualifier注解可以实现这一点。开箱即用,您可以使用字符串来限定 bean 和注入点:
@Autowired
@Qualifier("a")
Set<Foo> beansForContextA;
@Autowired
@Qualifier("b")
Set<Foo> beansForContextB;
@Configuration
public class Config {
@Bean
@Qualifier("a")
Foo bean1() {
...
}
@Bean
@Qualifier("b")
Foo bean2() {
...
}
}
但是,这在您的情况下不起作用,因为@Qualifier
的多个实例不能存在于同一个地方。您必须创建用Qualifier
注释的自定义注释,并使用这些注释而不是@Qualifier
和字符串名称。
@Target(value={FIELD,METHOD,PARAMETER,TYPE,ANNOTATION_TYPE})
@Retention(value=RUNTIME)
@Inherited
@Qualifier
public interface AScope
@Target(value={FIELD,METHOD,PARAMETER,TYPE,ANNOTATION_TYPE})
@Retention(value=RUNTIME)
@Inherited
@Qualifier
public interface BScope
使用这些自定义注释,您最终会得到这样的东西。
@Configuration
public class Config {
@Bean
@AScope
Foo bean1() {
...
}
@Bean
@BScope
Foo bean2() {
...
}
@Bean
@AScope
@BScope
Foo bean3() {
...
}
}
在注射点:
@Configuration
public class Impl {
@Autowired
@AScope
Set<Foo> beansForContextA;
@Autowired
@BScope
Set<Foo> beansForContextB;
public void execute() {
for (Foo foo : someCondition ? beansForContextA : beansForContextB) {
...
}
}
}
另一个简单的解决方案是使用新的注释.收集 bean by spring,并通过新的注释删除不需要的 bean。
public @interface BeanTag {
String value();
}
如何使用。
@Bean
Foo bean1TypeA() {
Foo foo = new Foo();
foo.setType("typeA");
return new Foo();
}
@Bean
Foo bean2TypeA() {
Foo foo = new Foo();
foo.setType("typeA");
return new Foo();
}
@Bean
Foo bean1TypeB() {
Foo foo = new Foo();
foo.setType("typeB");
return new Foo();
}
@Bean
Foo bean2TypeB() {
Foo foo = new Foo();
foo.setType("typeB");
return new Foo();
}
@Autowired
@BeanTag("typeA")
private Set<Foo> collectionTypeA;
@Autowired
@BeanTag("typeB")
private Set<Foo> collectionTypeB;
@PostConstruct
public void removeNotNeedType(){
// find all the field with @BeanTag remove not need bean
}