Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 春天不能';t自动连线,有多个``类型的bean_Java_Spring - Fatal编程技术网

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)));
    }
}