Java 在Spring中注入不同bean的多个实例
我正试图解决弹簧DI的一个问题。我有两个bean(Java 在Spring中注入不同bean的多个实例,java,spring,dependency-injection,Java,Spring,Dependency Injection,我正试图解决弹簧DI的一个问题。我有两个bean(MyFirstBean&MySecondBean),它们都实现了给定的接口(MyBean)。然后我有多个其他bean(例如,OtherBean),我想与这两个bean中的任何一个一起使用。对于OtherBean,自动连线显然失败,因为有多个MyBean实例可供选择。是否有可能为每个bean创建两个实例 自动连接MyBean并使用限定符引用它们?我知道通过编写一个配置类可以做到这一点,但由于所有这些都是API的一部分,因此我希望尽可能降低开销 当前
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;
}
}
所需情况:
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;
}
}
您可以向bean中添加@Qualifier来区分不同的bean。注入bean时,可以使用指定的限定符注入正确的bean。解决方案1: 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 ;
}
解决方案2:
有时我喜欢手动分配bean。所以我将所有可用bean自动关联到列表中,如下所示,然后在@PostConstruct中执行以下逻辑:
@Autowired
private List<MyBean> myBeans;
解决方案4:
自定义注释
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 ;
}
如果代码看起来与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;
}
}
我认为这是一个人能做的最简单的事情 创建一个处理器,请求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;
}
}
}
usage类看起来像这样
@Service
public class SomeServiceClass{
@Autowired private ProcessorFactory processorFactory;
//Other dependencies
void doSomething(Some args){
MyBean = processorFactory.getProcessor(arg);
//Do something with the object
}
}
尽管询问者希望避免编写配置类,但我使用配置类实现了一个解决方案,并且我想表明它真的没有那么糟糕 这是我的配置类:
@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
}
请尝试一下,让我知道它是否适合你 用正确的@Qualifier注释bean类,然后用所需的限定符自动连接bean。细微的差别很难解释。我可以向
OtherBean
添加一个限定符,从而解决冲突。但是我需要两个beanOtherFirstBean
,它使用MyFirstBean
,并进行相应的注释,还有OtherSecondBean
,它使用MySecondBean
。这不是我想要的。我想在自动连接OtherBean
时使用一个注释,并决定内部使用哪个beanOtherBean
。那么处理器(实现工厂模式)如何,它将在每次您要求它返回正确的实例时返回给您?工厂能否对不同的限定符注释作出反应?一个解决方案到底是什么样的?@fynn Checkout下面我的答案这是一个不错的解决方案,但我的问题是它需要一个额外的参数传递给doSomething方法,以便调用getProcessor来检索MyBean所需的实现。我希望不必更改SomeServiceClass的方法签名。有没有一种方法可以创建SomeServiceClass的两个不同实例,一个是MyFirstBean被注入的实例,另一个是MySecondBean被注入的实例?@JohnPeterThompsonGarcés看看重写getProcessor
是否能帮到你。[警告]这是一种糟糕的方法