Java 春天不能';t自动连线,有多个``类型的bean
我的问题是:我有一个基本接口和两个实现类 服务类依赖于基本接口,代码如下:Java 春天不能';t自动连线,有多个``类型的bean,java,spring,Java,Spring,我的问题是:我有一个基本接口和两个实现类 服务类依赖于基本接口,代码如下: @Component public interface BaseInterface {} 配置如下: @Configuration public class SpringConfig { @Bean public BaseInterface clazzImplA(){ return new ClazzImplA(); } @Bean public Base
@Component
public interface BaseInterface {}
配置如下:
@Configuration
public class SpringConfig {
@Bean
public BaseInterface clazzImplA(){
return new ClazzImplA();
}
@Bean
public BaseInterface clazzImplB(){
return new ClazzImplB();
}
}
服务类依赖于基础接口,将决定通过某些业务逻辑自动连接哪个实现。代码如下:
@Component
public interface BaseInterface {}
IDEA抛出了一个异常:无法自动连线。有多个bean属于
BaseInterface
类型
虽然可以使用@Qualifier来解决这个问题,但是在这种情况下,我不能选择dependencies类
@Autowired
@Qualifier("clazzImplA")
private BaseInterface baseInterface;
我试图阅读spring文档,它提供了一个基于构造函数的依赖注入,但我仍然被这个问题弄糊涂了
有人能帮我吗?如果使用
@Autowired
,Spring将搜索与要自动连线的字段类型匹配的bean。在您的例子中,有多个类型为BaseInterface
的bean。这意味着Spring不能毫不含糊地选择匹配的bean
在这种情况下,您没有其他选择来明确说明bean Spring应该使用或解决歧义。Spring在您的配置类中声明的两个bean之间混淆,因此您可以使用
@Qualifier
注释以及@Autowired
来通过指定确切的名称来消除混淆bean将被连接,在您的配置类上应用这些修改
@Configuration
public class SpringConfig {
@Bean(name="clazzImplA")
public BaseInterface clazzImplA(){
return new ClazzImplA();
}
@Bean(name="clazzImplB")
public BaseInterface clazzImplB(){
return new ClazzImplB();
}
}
然后在@autowired
注释处
@Service
@SpringApplicationConfiguration(SpringConfig.class)
public class AutowiredClazz {
@Autowired
@Qualifier("the name of the desired bean")
private BaseInterface baseInterface;
private AutowiredClazz(BaseInterface baseInterface){
this.baseInterface = baseInterface;
}
}
仅使用spring框架无法解决这一问题。您提到,基于某种逻辑,您需要一个BaseInterface实例。这个用例可以使用工厂模式来解决。创建一个Bean,它实际上是BaseInterface的工厂
@Component
public class BaseInterfaceFactory{
@Autowired
@Qualifier("clazzImplA")
private BaseInterface baseInterfaceA;
@Autowired
@Qualifier("clazzImplb")
private BaseInterface baseInterfaceB;
public BaseInterface getInstance(parameters which will decides what type of instance you want){
// your logic to choose Instance A or Instance B
return baseInterfaceA or baseInterfaceB
}
}
配置(无耻地从另一条评论中复制)
服务等级
@Service
@SpringApplicationConfiguration(SpringConfig.class)
public class AutowiredClazz {
@Autowired
private BaseInterfaceFactory factory;
public void someMethod(){
BaseInterface a = factory.getInstance(some parameters);
// do whatever with instance a
}
}
这里的回答是正确的,在接口由多个类实现的情况下,我们必须使用
@Component(name=$beanName)
我想再补充一点,在这种情况下,Spring甚至可以在地图中自动关联这样的bean:
@Autowired
Map<String,InterfaceName> interfaceMap;
//this will generate beans and index them with beanName as key of map
@Autowired
地图界面地图;
//这将生成bean,并使用beanName作为map的键对它们进行索引
更酷的解决方案是让实现本身包含逻辑,以确定它们是否适用。您可以将所有可用的实现作为一个集合注入,并对它们进行迭代,以找到一个(或多个,如果您需要的话)适用的实现:
public interface BaseInterface {
boolean canHandle(Object parameter);
Object doTheWork(Object parameter);
}
@Service
public class SomeService {
private final BaseInterface[] implementations;
// Spring injects all beans implementing BaseInterface
public MessageService(BaseInterface... implementations) {
this.implementations = implementations;
}
public Object doSomething(Object parameter) {
BaseInterface baseInterface = findBaseInterface(parameter);
return baseInterface.doTheWork(parameter);
}
private BaseInterface findBaseInterface(Object parameter) {
return Arrays.stream(implementations)
.findAny(i -> i.canHandle(parameter)
.orElseThrow(new MyRuntimeException(String.format("Could not find BaseInterface to handle %s", parameter)));
}
}
谢谢您的回答,但是在@Qualifier(“所需bean的名称”)这句话中,“所需bean的名称”可以是动态字符串吗?因为AutowiredClazz可能在不同的情况下使用不同的实现。spring无法处理此问题,因为
AutowiredClazz
将只初始化一次,但我注意到您有一个getInstance()
方法,它将返回适当的bean。这将使使用动态化您可能会认为Spring将实现一种简单的方法,尝试选择正确的方法,而不是在这里显示一个仅运行时的错误,在向用户显示错误之前很难解决该错误。很糟糕的实现,我讨厌这样的时刻Java@gdbjfacepalm是关于spring的,而不是java。在任何其他语言中,您都会遇到与DI相同的问题。如果您尝试将2个bean连接到一个字段,您将得到以下结果
@Service
@SpringApplicationConfiguration(SpringConfig.class)
public class AutowiredClazz {
@Autowired
private BaseInterfaceFactory factory;
public void someMethod(){
BaseInterface a = factory.getInstance(some parameters);
// do whatever with instance a
}
}
@Autowired
Map<String,InterfaceName> interfaceMap;
//this will generate beans and index them with beanName as key of map
public interface BaseInterface {
boolean canHandle(Object parameter);
Object doTheWork(Object parameter);
}
@Service
public class SomeService {
private final BaseInterface[] implementations;
// Spring injects all beans implementing BaseInterface
public MessageService(BaseInterface... implementations) {
this.implementations = implementations;
}
public Object doSomething(Object parameter) {
BaseInterface baseInterface = findBaseInterface(parameter);
return baseInterface.doTheWork(parameter);
}
private BaseInterface findBaseInterface(Object parameter) {
return Arrays.stream(implementations)
.findAny(i -> i.canHandle(parameter)
.orElseThrow(new MyRuntimeException(String.format("Could not find BaseInterface to handle %s", parameter)));
}
}