【问题标题】:How to inject two instances of two different classes which implement the same interface?如何注入实现相同接口的两个不同类的两个实例?
【发布时间】:2019-04-10 17:16:46
【问题描述】:

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

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

class MyClass {
  // ...
}

class XY {
  @Inject MyClass myClass;
}

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

class MyClass implements MyInterface {
  // ...
}

class XY {
  @Inject MyInterface myClass;
}

但是一旦我想注入不同的实现,我就会得到“Api type [...] is not found with the qualifiers”异常:

class MyClassOne implements MyInterface {
  // ...
}

class MyClassTwo implements MyInterface {
  // ...
}

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

我很欣赏尝试什么或在哪里继续阅读的任何想法(搜索此主题的明显关键字会给出非常不具体的结果)。 提前致谢!

【问题讨论】:

    标签: java cdi


    【解决方案1】:

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

    方法一

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

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

    @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 ...
    }
    

    【讨论】:

    • 非常感谢!这是一个很大的帮助。它还让我想到了第三种,甚至可能更简单的方法——为我的每个类引入另一个接口,然后扩展MyInterface 接口。
    猜你喜欢
    • 2012-08-02
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多