【问题标题】:How to setup a non-CDI bean from a 3rd party for @Inject into CDI bean如何从第三方为@Inject 设置非 CDI bean 到 CDI bean
【发布时间】:2015-04-11 05:05:52
【问题描述】:

虽然我在 CDI 中找到了设置 @Produces(有点像工厂)或使用 CDI javax.enterprise.inject.spi.Unmanaged 概念的示例,但他们似乎都认为 CDI 将是在其上创建类实例的人自己的条款和生命周期(这是有道理的)。

但是,在某些情况下,CDI 根本无法创建实例。

例如在内部创建对象并将其提供给您的第 3 方库(不使用 CDI 本身)。

现在,我如何获取这些已经实例化的对象(顺便说一下,它们是没有默认构造函数的最终对象),并让它们可供我的 CDI 托管 bean 使用?

这是一个简化的例子。

public class Foo
{
    @Inject
    private ByteBuffer buf;

    public void go()
    {
        // do something, with buffer
    }
}

public void process() {
    ByteBuffer buf = ByteBuffer.allocate(500);
    // TODO: how to add "buf" to current context?
    Foo foo = CDI.current().select(Foo.class,AnyLiteral.INSTANCE).get();
    foo.go();
}

现在,我意识到对于这个 特定 示例,我可以很容易地传入 ByteBuffer,或者为 ByteBuffer 设置一个 @Produces,甚至让 Foo 自己创建 ByteBuffer。 (所有这些都会更容易)。我选择了 ByteBuffer,因为它表现出我在使用 3rd 方库时遇到的相同问题

  • 实例是有效的 bean
  • 我无法控制其来源
  • 实例由库创建
  • 这些实例是 final,不能被包装、覆盖或代理

该用例还存在嵌套 CDI 引用的情况,这些引用也可以使用对此@Inject ByteBuffer buf; 的访问。

理想情况下,希望这是一种纯粹的 CDI api 技术,而不是特定于焊接或实现的东西。

我也开发了自定义范围创建,认为这可能是一个解决方案,有一种@BufferScope 来标识此实例的start() 和end()。但是对于 CDI 不能调用 newInstance() 或 produce() 的对象,没有一个示例和文档可以非常清楚地说明这一点。对象实例化不在我的掌控之中,但将其呈现给 CDI Scope 的能力是可能的,甚至可以管理该实例的最终死亡/销毁。

【问题讨论】:

  • 抱歉,我不明白 @Produces 的限制是什么让你需要这个。

标签: java cdi weld


【解决方案1】:

代理与包装不同。一种惯用的解决方法是创建一个ByteBufferHolder(在此处插入您的类),将自定义构建器流程调整为一个能够理解它位于 DI 上下文中的 bean。

【讨论】:

  • 我假设您的“进入 bean”是指 CDI javax.enterprise.inject.spi.Bean,那么一旦您拥有实例,获取有效 CDI Bean 引用的正确方法是什么,所有技术似乎都假设您从 Class 开始,然后实例由 CDI 提供。 (猜猜我要的是一个例子,或者我只是缺少的一点 javadoc)
【解决方案2】:

我不确定我是否同意 CDI 假设它正在构建实例的原始断言。例如,我在 JSF 应用程序中使用以下代码来注入当前的 FacesContext 实例......

import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;

public class FacesContextProducer {

    @Produces @RequestScoped FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }
}

我在任何地方都没有创建 FacesContext 实例。所需要的只是外部框架创建的内容是可访问的。

那么,如果您从外部来源获取实例,只要您能获得正确的来源,@Produces 方法应该仍然有效吗?

【讨论】:

    【解决方案3】:

    这里有一些基本的误解。 CDI 不需要构造它可以通过生产者方法服务的 bean 实例。如果类不可代理,则从属范围可以正常工作。您还可以为对象创建一个包装类,并将所述类实例放在您需要的任何范围内。

    【讨论】:

      【解决方案4】:

      您使用生产者方法,它可以像这样简单:

      @Produces
      @ApplicationScoped
      private Foo produceFoo() {
        final Foo instance = // acquire one of those instances you're talking about
        return instance;
      }
      

      如果由于某种原因对您不起作用,您也可以编写一个可移植的扩展程序并以编程方式添加一个 Bean 来满足您的需求。所以在 CDI 2.0+ 中是这样的(未经测试):

      private void afterBeanDiscovery(@Observes final AfterBeanDiscovery event) {
        final Foo instance = // acquire one of these final instances you're talking about
        event.addBean()
          .scope(ApplicationScoped.class)
          .qualifiers(whateverYouNeed)
          .addTransitiveTypeClosure(instance.getClass())
          .createWith(cc -> instance) // you may also need .destroyWith()
          ;
      }
      

      一旦你设置了这个“生产方”,然后在任何你可以做的任何 CDI bean 中:

      @Inject
      private Foo foo;
      

      【讨论】:

        猜你喜欢
        • 2013-12-07
        • 1970-01-01
        • 2015-04-20
        • 2011-05-07
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        • 2019-03-03
        • 1970-01-01
        相关资源
        最近更新 更多