如何告诉 CDI 容器“激活”一个 bean?
Posted
技术标签:
【中文标题】如何告诉 CDI 容器“激活”一个 bean?【英文标题】:How can I tell the CDI container to "activate" a bean? 【发布时间】:2018-02-12 01:29:26 【问题描述】:假设我有一些注射类:
class MyBean
@Inject
Helper helper;
// all sorts of data
并且这个类是以 CDI 容器不知道的方式创建的,例如反射、序列化或new
。在这种情况下,helper
是 null
,因为 CDI 没有为我们初始化它。
有没有办法告诉 CDI “激活” bean 或至少它的注入?例如,好像它是用 Instance<MyBean>#get
创建的?
现在我有一个技巧,我可以在其中执行以下操作:
class SomeClass
@Inject
Instance<MyBean> beanCreator;
void activateBean()
MyBean mybean = ... // reflection/serialization/new
MyBean realBean = beanCreator.get();
Helper proxy = realBean.getHelper();
mybean.setHelper(proxy);
beanCreator.destroy(realBean);
这看起来很糟糕,但它适用于我测试的所有内容。它只是显示了我想要的最终结果。
如果重要,请使用 Wildfly 10.1。
【问题讨论】:
【参考方案1】:首先,你使用MyBean
的方式不是CDI方式;实际上,您对所谓的非上下文对象进行操作。您正在做的是获取非 CDI 托管对象并要求 CDI 解析注入点。这是非常不寻常的,因为您处理生命周期的一部分(创建/销毁),而要求 CDI 完成其余的工作。
在你的情况下,MyBean
类需要变成InjectionTarget
,这就是你应该开始寻找的方式。为了触发注入,您需要执行以下操作(在创建 MyBean
期间):
// Create an injection target from your given class
InjectionTarget<MyBean> it = beanManager.getInjectionTargetFactory(beanManager.createAnnotatedType(MyBean.class))
.createInjectionTarget(null);
CreationalContext<MyBean> ctx = beanManager.createCreationalContext(null);
MyBean instance = new MyBean();
it.postConstruct(instance); // invoke @PostContruct
it.inject(instance, ctx); // trigger actual injection on the instance
请注意,这种方法通常很笨拙(因为很难使其工作和维护),最好将您的 MyBean
变成真正的 CDI bean 并将整个生命周期管理留给 CDI。但是,为此,您的问题没有提供足够的信息。
【讨论】:
谢谢。上下文:MyBean
是我需要保存和加载的状态对象的一部分,目前带有序列化(参见我之前的question)。我读到在实体中使用注入不是一个好主意,但这个实体需要它。另外,你写new MyBean()
的地方可以用反序列化或反射代替,对吧?
或许你应该考虑一下,是否合理且有必要赋予 MyBean 使用 Helper 履行的职责。有时结构会更好,如果你让一些Decorator
、Adaptor
甚至Iterator
处理它。这些通常是可以由容器创建的正常范围的 bean,并且能够与您的数据对象一起使用。
如果您提供用例,说明实体实际上如何依赖此类 bean,那么我们可以帮助将其重构为更好的设计,无需注入实体。理想情况下,您应该将实体视为数据,并有一个单独的 bean 来处理该数据
@Mark 是的,我认为您可以使用反序列化。我的示例中该行的重点是获取对实际实例的引用。所以它应该可以工作。
我对此进行了测试,bean 的注入是 null
所以它不能按原样工作:(以上是关于如何告诉 CDI 容器“激活”一个 bean?的主要内容,如果未能解决你的问题,请参考以下文章