如何告诉 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。在这种情况下,helpernull,因为 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 履行的职责。有时结构会更好,如果你让一些DecoratorAdaptor 甚至Iterator 处理它。这些通常是可以由容器创建的正常范围的 bean,并且能够与您的数据对象一起使用。 如果您提供用例,说明实体实际上如何依赖此类 bean,那么我们可以帮助将其重构为更好的设计,无需注入实体。理想情况下,您应该将实体视为数据,并有一个单独的 bean 来处理该数据 @Mark 是的,我认为您可以使用反序列化。我的示例中该行的重点是获取对实际实例的引用。所以它应该可以工作。 我对此进行了测试,bean 的注入是 null 所以它不能按原样工作:(

以上是关于如何告诉 CDI 容器“激活”一个 bean?的主要内容,如果未能解决你的问题,请参考以下文章

spring Environment

使用 CDI/Weld 注入通用 Bean

如何检测是否从键盘的容器应用程序激活自定义键盘?

JSF、CDI 和 EJB 容器:应该使用它们的哪种组合?

25自动装配-@Profile根据环境注册bean

将较短范围的 Bean 实例注入 CDI 中较大范围的 bean 实例 - 它是如何工作的?