如何注入两个实现相同接口的不同类的实例?

问题描述 投票:0回答:1

在java中处理CDI时,我想注入两个不同类的两个实例,实现相同的接口。

据我所知,我可以注入一个没有实现接口的类的实例,例如:

class MyClass {
  // ...
}

class XY {
  @Inject MyClass myClass;
}

当我的类实现一个接口时,我必须通过接口名声明成员(并指定具体的实现):

class MyClass implements MyInterface {
  // ...
}

class XY {
  @Inject MyInterface myClass;
}

但是一旦我想注入不同的实现,我得到“Api类型[...]找不到限定符”异常:

class MyClassOne implements MyInterface {
  // ...
}

class MyClassTwo implements MyInterface {
  // ...
}

class XY {
  @Inject MyClassOne myClassOne;
  @Inject MyClassTwo myClassTwo;
}

我感谢任何想法尝试或继续阅读的内容(搜索此主题的明显关键字给出了非常不明确的结果)。提前致谢!

java cdi
1个回答
2
投票

为了注入不同的实例,有不同的方法来构造和注入bean。

方法1:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ClassifierOne {
}

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ClassifierTwo {
}

这些限定符可用于构造参数注入或setter注入级别的类部分。

@ClassifierOne
public class MyClassOne implements MyInterface {
  // ...
}

@ClassifierTwo
public class MyClassTwo implements MyInterface {
 // ...
}

public class XY {
   private final MyInterface myClassOne;
   private final MyInterface myClassTwo;

   @Inject
   public XY ( @ClassifierOne MyInterface myClassOne, @ClassifierTwo MyInterface myClassTwo ) {
         this.myClassOne = myClassOne;
         this.myClassTwo = myClassTwo;
   }
}

方法2:使用@Produces

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface MyClassType {
    ClassImplName value();
}

public enum ClassImplName {
    CLASS_ONE(MyClassOne.class),
    CLASS_TWO(MyClassTwo.class);

    private Class<? extends MyInterface> classType;

    private ClassImplName(Class<? extends MyInterface> clazz) {
        this.classType = clazz;
    }

    public Class<? extends MyInterface> getClassType(){
        return classType;
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface ClassType {
    ClassImplName value();
}

上面的自定义限定符将允许您通过删除生成器方法中的abibuaty来选择实现类型。并且,您可以使用下面提到的MyClassFactory来生成接口。这种机制是有效的,因为它使用注入bean的InjectionPoint。

public class MyInterfaceFactory {

    @Produces
    @MyClassType
    public MyInterface createMyClasses(@Any Instance<MyInterface> instance, InjectionPoint injectionPoint) {
        Annotated annotated = injectionPoint.getAnnotated();
        ClassType classTypeAnnotation = annotated.getAnnotation(ClassType.class);
        Class<? extends MyInterface> classType = classTypeAnnotation.value().getClassType();
        return instance.select(classType).get();
    }
}

最后,您可以在类中使用这些生成的实例。

public class XY {

    @Inject
    @ClassType(ClassImplName.CLASS_ONE)
    @MyClassType
    private MyInterface myClassOne;

    @Inject
    @ClassType(ClassImplName.CLASS_TWO)
    @MyClassType
    private MyInterface myClassTwo;

    // Other methods using injected beans ...
}
© www.soinside.com 2019 - 2024. All rights reserved.