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

时间:2019-04-10 17:16:47

标签: java cdi

在用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;
}

对于任何尝试尝试或在哪里继续阅读的想法,我都表示感谢(搜索该主题的明显关键字会给出非常不确定的结果)。 预先感谢!

1 个答案:

答案 0 :(得分:2)

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

方法1

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

这些限定符可用于您的施工参数注入或设置器注入级别的班级部分。

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

方法2 :使用@Produces

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

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

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

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

:SetVar DatabaseSchema "SALES_MART"

CREATE SCHEMA $(DatabaseSchema);
GO

CREATE TABLE $(DatabaseSchema).SalesReport  
( 
     id INT,
     SaleDate DATETIME2,
     sales INT,
     Categoryname VARCHAR(100)
);
GO

INSERT INTO $(DatabaseSchema).SalesReport  
VALUES (1, '1905-07-08 00:00:00.000', 50, 'Asia'),
       (2, '1905-07-08 00:00:00.000', 90, 'Asia'),
       (3, '1905-07-08 00:00:00.000', 100, 'EU');

DECLARE @max_date DATETIME2

SET @max_date = CASE 
                   WHEN EXISTS(SELECT MAX(SaleDate)
                               FROM  $(DatabaseSchema).SalesReport
                               WHERE Categoryname = 'Asia')
                      THEN (SELECT MAX(SaleDate)
                            FROM  $(DatabaseSchema).SalesReport
                            WHERE Categoryname = 'Asia')
                      ELSE GETDATE()
                END

PRINT @max_date

-- Clean up
DROP TABLE $(DatabaseSchema).SalesReport;
GO

DROP SCHEMA $(DatabaseSchema);
GO