CDI 动态 Bean 实例
Posted
技术标签:
【中文标题】CDI 动态 Bean 实例【英文标题】:CDI Dynamic Bean Instances 【发布时间】:2016-08-05 06:18:17 【问题描述】:使用 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;
您可以创建一个制作动物的 Producer 方法,例如使用限定符来制作某种动物:
@Produces @AnimalType
public Animal makeAnimal(InjectionPoint ip)
// Get AnimalType qualifier and make a new Animal(typeString),
// ...
return animal;
但是您如何生成所有(从数据中得知)动物,以便您可以通过实例对它们进行迭代?
for(Animal animal : animals)
// ...
我确实希望每只动物都能从依赖注入和其他 Weld/CDI 好东西中受益。
【问题讨论】:
【参考方案1】:您可能正在寻找Unmanaged
Unmanaged<Animal> unmanagedAnimal = new Unmanaged<>(Animal.class);
UnmanagedInstance<Animal> animalInstance = unmanagedAnimal.newInstance();
Animal animal = animalInstance.produce().inject().postConstruct().get();
它基本上是一个依赖作用域的bean,但你需要在完成后手动销毁它。
【讨论】:
非托管它用于转换注入目标中的非 bean 类。这里需要能够在任何地方注射动物。非托管是不够的。唯一的解决办法就是把这些动物做成豆子……【参考方案2】:据我了解 InjectionPoint 概念,您不能以这种方式将其与 Instance 一起使用。 Instance 和 InjectionPoint 与 producer-method 用于注入
Instance<Animal>
与所有 CDI 动物一起进入生产者方法,然后让生产者方法决定返回哪个动物,具体取决于 InjectionPoint:
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));
但是在这种情况下,您必须为每个选择情况编写一个生产者方法。恐怕,那不合适。
要使用 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");
但是由于缺少限定符 AnimalType,您不能将 Instance 注入到您的 bean 中。所以你必须像这样生成一个简单的列表:
@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;
【讨论】:
以上是关于CDI 动态 Bean 实例的主要内容,如果未能解决你的问题,请参考以下文章
获取 CDI 托管 bean 实例的规范方法:BeanManager#getReference() 与 Context#get()
如何以编程方式将 Java CDI 托管 bean 注入(静态)方法中的局部变量
CDI + JPA 多个 @OneToMany - LAZY/EAGER - LazyInitializationException 或无法实例化多个包