【问题标题】:Are CDI.current().select().get() and BeanManager.getReference() functionally equivalent?CDI.current().select().get() 和 BeanManager.getReference() 在功能上是否相同?
【发布时间】:2019-04-02 12:47:39
【问题描述】:

在 JEE/CDI 的上下文中,当我需要从方法中静态检索 CDI 托管 bean 时,我发现自己通常使用 CDI 静态函数。例如:

MyBean myBean = CDI.current().select( MyBean.class ).get()

但是,据我所知,另一种等效的方法是使用 BeanManager:

BeanManger bm = new InitialContext().lookup( "java:comp/BeanManager" );
Bean<?> bean = bm.resolve(bm.getBeans( MyBean.class ) );
CreationalContext<?> context = bm.createCreationalContext(bean);
MyBean myBean = bm.getReference(bean, cls, context);

所以除了使用CDI.current() 方法编写的代码明显减少之外,使用它有什么不同?似乎恢复使用BeanManager 是一种更复杂(并且可能容易出错?)的方法。从功能的角度来看,使用CDI.current() 方法有什么缺点吗? CDI...select() 是否仅适用于 @ApplicationScope bean?或者我也可以与其他作用域 bean 一起使用(例如:@Dependent)吗?

我记得读过一些关于使用 CDI 方法可能发生内存泄漏的文章,但不明白这是如何发生的或为什么会发生这种情况。

【问题讨论】:

    标签: java jakarta-ee cdi


    【解决方案1】:

    我们使用这些方法在您的非 CDI 代码中访问 CDI。在 CDI 代码中,我们可以注入 BeanManager 和您的 bean。

    JNDI 查找用于 CDI 1.0。在 CDI 1.1 之后,我们应该使用 CDI 类及其静态方法。

    http://www.next-presso.com/2016/02/cdi-the-spi-who-loved-me/

    在 CDI 1.0 中,您必须访问 CDI bean 图的唯一解决方案是从 JNDI 检索 BeanManager ... 这种冗长证明 BeanManager 是高级 CDI 工具,允许在 CDI 回显系统上进行非常基本的操作。如果您只想访问一个实例,这显然不是最好的解决方案。 这就是为什么在 CDI 1.1 中我们引入了抽象 CDI 类,它使用 Java Service Loader 从实现中检索具体的 CDI 类。 ... 检索实例变得如此简单

    CDI<Object> cdi = CDI.current();
    MyService service = cdi.select(MyService.class).get();
    

    【讨论】:

      【解决方案2】:

      两种方法产生相似的结果,但是有两个主要区别。

      • CDI.current() 是你能做到的,而你不能简单地 @Inject BeanManager
        • 这只是一种从非 cdi 托管对象中获取 CDI 实例的方法
      • Instance.get() 不采用 CreationalContext 参数,而 BM.getReference() 采用。
        • 这是一个关键的区别,当使用Instance 时,CreationalContext 是由容器管理的——你不需要关心它,尤其是释放上下文。如果您使用BM.getReference(),您首先需要获取该上下文,这通常意味着创建它,并且您有责任在完成使用它后发布它。

      【讨论】:

      • 感谢您的洞察力。应该如何释放上下文?从我释放上下文时从 javadoc 收集的内容中,我还销毁了它检索到的所有 bean。这是否意味着上下文将与容器的 CDI 的上下文不同? (甚至不确定这怎么可能)。如果不是,释放上下文不就等于销毁容器的上下文bean吗?
      • CreationalContext.release() 是您发布它的方式。它需要让 CDI 容器处理与这些实例挂钩的任何相关的预销毁方法(或如果这些 bean 是通过生产者生成的处置方法)以及销毁实例本身。
      • 但这是否暗示他们,如果我通过 @Inject 从容器的上下文中检索一个 ApplicationScoped bean,并从 BM.createCreationalContexr 检索一个,我实际上将有 2 个不同的 @AS bean使用 2 种不同的上下文?如果是这样,我将如何使用 BM 从容器管理的上下文中检索 bean(没有CDI.current())?
      • 继续测试它 - 你将拥有相同的 bean(可能不同的代理但相同的底层上下文实例)。否则它将违背 AppScoped 的全部观点。 CreationalContext 不是“真正的 CDI 含义”中的上下文(如请求、会话、...上下文),它只是帮助将实际的上下文 bean 和链接到它的依赖实例粘合在一起。请看规范中的this chapter
      猜你喜欢
      • 2015-02-27
      • 2019-06-05
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-10
      相关资源
      最近更新 更多