我正在尝试解决Spring DI的问题。我有两个bean(MyFirstBean
& MySecondBean
),它们都实现了一个给定的接口(MyBean
)。然后我有多个其他bean(例如OtherBean
),我想与两个bean中的任何一个一起使用。 OtherBean
的自动装配显然失败,因为有多个MyBean
个实例可供选择。是否有可能一般地创建每个bean的两个实例
自动装配MyBean
并使用限定符引用它们?我知道这可以通过编写配置类来实现,但由于所有这些都是API的一部分,我希望尽可能降低开销。
现状:
public interface MyBean {
}
@Component
public class MyFirstBean implements MyBean {
}
@Component
public class MySecondBean implements MyBean {
}
@Component
public class OtherBean {
final MyBean myBean; // error due to multiple beans
public OtherBean(MyBean myBean) {
this.myBean = myBean;
}
}
期望情况:
@Component
public class SomeBean {
final OtherBean myBeanUsingFirstBean; // internally autowires MyFirstBean
final OtherBean myBeanUsingSecondBean; // internally autowires MySecondBean
public SomeBean(
@FirstBeanQualifier OtherBean myBeanUsingFirstBean,
@SecondBeanQualifier OtherBean myBeanUsingSecondBean) {
this.myBeanUsingFirstBean = myBeanUsingFirstBean;
this.myBeanUsingSecondBean = myBeanUsingSecondBean;
}
}
答案 0 :(得分:5)
spring autowires bean的方法之一就是名字。如果没有指定,spring将使用类名创建bean(带小的首字母),因此对于MyFirstBean,bean名称将是myFirstBean。知道你可以通过将属性的名称更改为最终的MyBean myFirstBean来自动装配所需的bean
public interface MyBean {
}
@Component
public class MyFirstBean implements MyBean {
}
@Component
public class MySecondBean implements MyBean {
}
@Component
public class OtherBean {
// this way spring will inject instance of MyFirstBean
@Autowired
final MyBean myFirstBean ;
}
有时我喜欢手动分配bean。所以我将所有可用的bean自动装入列表中,然后在@PostConstruct中使用逻辑:
@Autowired
private List<MyBean> myBeans;
使用@Qualifier注释
public interface MyBean {
}
@Component("fooBean")
public class MyFirstBean implements MyBean {
}
@Component
public class MySecondBean implements MyBean {
}
@Component
public class OtherBean {
@Autowired
@Qualifier("fooBean")
final MyBean myFirstBean ;
}
自定义注释
@Qualifier
@Target({
ElementType.FIELD, ElementType.METHOD, ElementType.TYPE,
ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBeanType {
String value();
}
public interface MyBean {
}
@MyBeanType("fooBean")
@Component()
public class MyFirstBean implements MyBean {
}
@MyBeanType("barBean")
@Component
public class MySecondBean implements MyBean {
}
@Component
public class OtherBean {
@Autowired
@MyBeanType("Foo")
final MyBean myBean ;
}
答案 1 :(得分:1)
您可以将@Qualifier添加到bean中以区分不同的bean。注入bean时,您可以使用指定的限定符注入正确的限定符。
答案 2 :(得分:0)
如果代码应该像OP所描述的那样完全,那么自定义注释就足够了:
@Qualifier("myFirstBean")
@Retention(RetentionPolicy.RUNTIME)
public @interface FirstBeanQualifier {}
@Qualifier("mySecondBean")
@Retention(RetentionPolicy.RUNTIME)
public @interface SecondBeanQualifier {}
@Component
public class OtherBean {
private final MyBean myBean1;
private final MyBean myBean2;
public OtherBean(@FirstBeanQualifier MyBean myBean1,
@SecondBeanQualifier MyBean myBean2) {
this.myBean1 = myBean1;
this.myBean2 = myBean2;
}
}
答案 3 :(得分:0)
我认为这可能是最简单的事情。
创建一个处理器,请求MyBean类型的对象
@Component
public class ProcessorFactory {
@Autowired private MyFirstBean myFirstBean;
@Autowired private MySecondBean mySecondBean;
public MyBean getProcessor(arg) {
if (arg == SomeValue1) {
return myFirstBean;
}else{
return mySecondBean;
}
}
}
用法类看起来像这样
@Service
public class SomeServiceClass{
@Autowired private ProcessorFactory processorFactory;
//Other dependencies
void doSomething(Some args){
MyBean = processorFactory.getProcessor(arg);
//Do something with the object
}
}
答案 4 :(得分:0)
尽管问问者希望避免编写Configuration类,但我使用一个实现了一个解决方案,并且想证明它确实还不错。
这是我的配置类:
@Configuration
public class ApplicationContextOtherBeanQualifier {
@Autowired
@Qualifier("myFirstBean")
private MyBean myFirstBean;
@Autowired
@Qualifier("mySecondBean")
private MyBean mySecondBean;
// Here is how you get two different instances of OtherBean
// while using the same implementation:
@Bean
public OtherBean otherBeanUsingFirstBean() {
return new OtherBean(myFirstBean);
}
@Bean
public OtherBean otherBeanUsingSecondBean() {
return new OtherBean(mySecondBean);
}
}
现在,您可以使用@Resource
和@Qualifier
批注将其适应所需的情况:
@Component
public class SomeBean {
@Resource
@Qualifier("otherBeanUsingFirstBean")
private OtherBean otherBeanUsingFirstBean; // internally autowires MyFirstBean
@Resource
@Qualifier("otherBeanUsingSecondBean")
private OtherBean otherBeanUsingSecondBean; // internally autowires MySecondBean
}
请尝试一下,让我知道它是否适合您!