【问题标题】:Spring Bean implementing multiple interfacesSpring Bean 实现多个接口
【发布时间】:2015-10-09 11:32:01
【问题描述】:

我有一个实现两个接口的 bean。准系统代码如下:

interface InterfaceA {
  ...
}

interface InterfaceB {
  ...
}

public class ClassC implements InterfaceA, InterfaceB {
  ...
}

在我的 AppConfig 中,我指定了以下内容:

@Bean(name = "InterfaceA")
public InterfaceA interfaceA() {
    return new ClassC();
}

@Bean(name = "InterfaceB")
public InterfaceB interfaceB() {
    return new ClassC();
}

我是这样使用它的:

public class MyClass {

    @Inject
    private final InterfaceA a;

    public MyClass(@Named("InterfaceA") InterfaceA a) {
        this.a = a;
    }
     ...
}

但是,Spring 抱怨说:

没有符合条件的 bean 类型 [com.example.InterfaceA] 是 已定义:预期的单个匹配 bean,但找到了 2: 接口A、接口B

针对 EJB here 提出并回答了类似问题,但我找不到 Spring bean 的任何内容。有人知道原因吗?

解决方法是引入一个扩展InterfaceAInterfaceB 的新接口,然后让ClassC 实现它。但是,由于框架限制,我不愿意改变我的设计。

【问题讨论】:

  • 为什么...只需创建ClassC 的单个实例... 方法的返回类型在这里无关紧要,因为bean 将是InterfaceAInterfaceB。你不需要额外的接口...

标签: java spring dependency-injection inject


【解决方案1】:

感谢您提出的精彩问题。

就我而言,我创建了一个同时扩展 A 和 B 的接口:

public interface InterfaceC extends InterfaceA, InterfaceB {}

...通用实现实现统一接口:

public class ClassC implements InterfaceC {
  //...
}

这个统一的接口允许创建单个 bean:

@Bean
public InterfaceC implementationForAandB() {
    return new ClassC();
}

然后,Spring 框架能够将通用实现注入或自动装配到以主接口表示的依赖项:

public class MyClass {

    @Inject
    private final InterfaceA a;

    @Inject
    private final InterfaceB b;

    public MyClass(InterfaceA a, InterfaceB b) {
        //...
    }

}

【讨论】:

    【解决方案2】:

    春天是对的……当你写的时候

    @Bean(name = "InterfaceA")
    public InterfaceA interfaceA() {
        return new ClassC();
    }
    
    @Bean(name = "InterfaceB")
    public InterfaceB interfaceB() {
        return new ClassC();
    }
    

    Spring 为ClassC 创建对象,一个名为InterfaceA,另一个名为InterfaceB,都实现了InterfaceA 和InterfaceB。

    那么当你写的时候:

    @Inject
    private final InterfaceA a;
    

    你要求Spring找一个bean实现InterfaceA,但是上面说有2个所以报错。

    您可以只创建一个ClassC 类型的对象,或者使用@Qualifier@Named 注释:

    @Inject
    @Named("InterfaceA")
    private final InterfaceA a;
    

    这样,您明确要求 Spring 找到 named InterfaceA 的 bean,并希望它现在是唯一的。

    【讨论】:

    • 谢谢。将@Named 添加到该字段已修复它。我会接受你的回答。但是,我确实用@Named 注释了构造函数参数。为什么这还不够?这不是告诉 Spring 使用正确的 bean 吗?
    • @341008 :如果您的 bean 创建使用带有 @Named 注释的构造函数,它应该可以工作......前提是您删除了 a 属性上的 @Inject。如果没有,只要构造了MyClass 对象,Spring 就会尊重@Inject 注释并尝试使用InterfaceA bean 设置a 并找到其中的两个。
    • 哦,我明白了。我为构造函数参数设置@Named,在字段上设置@Inject。然后我将不得不删除@Inject。谢谢。
    猜你喜欢
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 2019-09-03
    • 2021-09-03
    • 1970-01-01
    相关资源
    最近更新 更多