【问题标题】:@Produces does not return cdi proxy, but real instance@Produces 不返回 cdi 代理,而是真实实例
【发布时间】:2019-09-25 05:34:24
【问题描述】:

我有课

@RequestScoped
public class AFactory {

  private final HttpServletRequest request;

  protected AFactory () {
    this.request = null;
  }

  @Inject
  public AFactory (HttpServletRequest request) {
    this.request = request;
  }

  @Produces
  public A getA() {
    int random = ...;
    A a = new A(request);
    a.setRandom(random);
    return a;
  }

}

我明白了,因为我在做new A(),所以我返回了真实的实例。

这是使用生产者的预期方式吗?

有没有办法返回代理实例?

【问题讨论】:

  • Afaik,用@Produces 注释的方法实际上是代理。该方法是“注入”的。因此,您在每次调用它时都会获得一个新实例,因为您每次都在方法中创建一个新实例。如果你'lazy'实例化它,你每次都会得到相同的A,所以不需要代理。但我可能错了……
  • 关于“正确的方式(或错误的方式)”是完全的;;y 取决于您的用例...您是否需要 A 的状态在调用之间保持一致(您的“随机” ) 或不。如果没有,你使用它的方式就可以了,如果它需要相同,就偷懒吧。
  • @Kukeltje 我需要它是 @RequestScoped,因此,同一个实例,在该请求期间使用它的所有 bean 之间具有完全相同的随机数
  • 然后在构造函数中执行或在 getter 中执行'lazy'...简单的所有基本 java。
  • 虽然我的回答“解决了”你的问题,但我对它为什么表现得像你看到的那样的假设是错误的。它通过解决 CDI 行为并以传统的 java 方式解决它来解决它。请不接受我的答案并接受另一个答案,以便我删除我的答案。

标签: cdi factory


【解决方案1】:

CDI 为除@Dependent pseudo scope 之外的所有范围的bean 安装proxies。每当需要获取 bean 的(新)实例时,CDI 都会调用 @Produces 带注释的方法(简称 producer)。然后将此实例放入相应范围的某个池中。

代理将始终从池中返回 bean-instance。尝试向生产者方法添加一些调试消息,以查看它被调用的频率。 @ApplicationScoped bean 的生产者应该只调用一次,@RequestScoped 生产者应该在每个请求中调用一次。

在上面的示例中,没有给生产者方法指定范围(工厂类的范围不用于生产者方法),因此将使用默认范围(@Dependent)。这意味着(因为此范围没有使用代理),每次 CDI 找到 @Inject A 时都会注入一个新实例。另请参阅Question and Answer 和参考文档了解更多详细信息。

所以对于你的具体问题:

  • 观察到的行为是预期的
  • 只有在默认范围不是@Dependet 时才会使用代理。

【讨论】:

  • 这确实是正确的。只需添加一点点 - @javax.inject.Singleton不是 EJB !)也是一个无代理作用域,并且将始终使用真实实例。
猜你喜欢
  • 2019-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 2015-02-01
相关资源
最近更新 更多