CDI动态Bean实例

时间:2016-04-13 22:11:57

标签: java cdi wildfly java-ee-7 weld

使用Wildfly / JBoss Weld / CDI 1.1。

假设你有一个数据库。可以是任何东西,MySQL,MongoDB。可以是REST服务。从该数据库中,您可以获得动物列表。

[
  "Cat",
  "Dog",
  "Giraffe",
  "Tiger",
  "Chicken"
]

您不知道您将从此服务中获得哪些动物,但您想要做的是将它们用于实例注射。

动物类:

public class Animal {
  private final String type;
  public String getType() {
    return type;
  }
  public Animal(String aType) {
    type = aType;
  }
}

注射点:

@Inject @Any
public Instance<Animal> animals;

你可以制作一个制作AN动物的制作人方法,例如用限定词来制作某种动物:

@Produces @AnimalType
public Animal makeAnimal(InjectionPoint ip) {
  // Get AnimalType qualifier and make a new Animal(typeString), 
  // ...
  return animal;
}

但是,如何生成ALL(从数据中获知)动物,以便您可以使用实例迭代它们?

for(Animal animal : animals) {
  // ...
}

我确实希望每个Animal都能获得依赖注入和其他Weld / CDI好处的好处。

2 个答案:

答案 0 :(得分:1)

您好像在寻找Unmanaged

Unmanaged<Animal> unmanagedAnimal = new Unmanaged<>(Animal.class);
UnmanagedInstance<Animal> animalInstance = unmanagedAnimal.newInstance();
Animal animal = animalInstance.produce().inject().postConstruct().get();

它基本上是一个依赖的scoped bean,但你需要在完成时手动销毁它。

答案 1 :(得分:0)

据我了解InjectionPoint概念,您不能以这种方式将它与Instance一起使用。带有producer-method的Instance和InjectionPoint用于注入

 Instance<Animal>

进入带有所有CDI动物的生产者方法,让生产者方法决定,返回哪种动物,取决于注射点:

 public Animal make(@Any Instance<Animal> instance, InjectionPoint ip)

另见https://www.javacodegeeks.com/2013/06/java-ee-cdi-programmatic-dependency-disambiguation-example-injection-point-inspection.html

或者生成一个已配置的对象,具体取决于Qualifier-Config-Inputs,例如https://dzone.com/articles/cdi-di-p2

在你的情况下,你必须告诉CDI,如何找到生产者方法:

  @Qualifier
  @Retention(RUNTIME)
  @Target({TYPE, METHOD, FIELD, PARAMETER})
  public @interface AnimalType {
      String value();   
  }

然后你可以编写适当的生成器方法:

@Produces
@AnimalType("Monkey")
public Animal makeAnimalApe() {
    return new Animal("Cheetah");
}


@Produces
@AnimalType("Mouse")
public Animal makeAnimalMouse() {
    return new Animal("Jerry");
}

@Produces
@AnimalType("Cat")
public Animal makeAnimalCat() {
    return new Animal("Tom");
}

然后你可以注射它:

@Inject
@Any
private Instance<Animal> anyAnimal;

@Inject
@AnimalType("Monkey")
private Animal monkey;

@PostConstruct
public void create(){
    System.out.println(monkey.name);
    anyAnimal.forEach((a)->System.out.println(a.name));
}

但在这种情况下,你必须为每个选择案例编写一个producer-method。我担心,那不合适。

要使用InjectionPoint,您可以使AnimalType不是限定符

@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface AnimalType {
    String value(); 
}

现在你必须使用InjectionPoint:

@Produces
public Animal makeAnimalApe(InjectionPoint p) {
    AnimalType t = p.getAnnotated().getAnnotation(AnimalType.class);
    if (t != null) {
        String s = t.value();
        if ("Monkey".equals(s))
            return new Animal("Cheetah");
        else if ("Mouse".equals(s))
            return new Animal("Jerry");
        else if ("Cat".equals(s))
            return new Animal("Tom");
    }       
    throw new EJBException("Please annotate the animal injection point with AnimalType");
}

但是你不能将Instance注入你的bean,因为缺少Qualifier AnimalType。所以你必须像这样产生一个简单的List:

@Produces
public List<Animal> produceAll(){
    List<Animal> all = new ArrayList<>();
    all.add(new Animal("Cheetah"));
    all.add(new Animal("Jerry"));
    all.add(new Animal("Tom"));
    return all;
}

所以你可以只注射一个或所有

@Inject
@AnimalType("Monkey")
private Animal monkey;
@Inject
private List<Animal> all;