EJB @Singleton Weld 代理实例数量稳步增加

Steadily Increasing number of EJB @Singleton Weld Proxy Instances

我们有一个 EJB @Singleton,因为我们可以从中受益:

EJB 单例是 EAR 部署的一部分。为了能够在不在 EJB 或 CDI 范围内的遗留代码中使用它,我们目前使用 CDI.current().select(<type-of-singleton-EJB>).get().

之类的东西手动注入它

现在我们注意到该单例的 $Proxy$_$$_Weld$EnterpriseProxy$$$$viewxxx 实例数量稳步增加,我认为这是因为对于 CDI,EJB @Singleton 在@Dependent pseudo scope 所以所有那些手动注入的实例只要我们的遗留代码 class 就可以存在,这可能与应用程序的生命一样长。 请注意,它只是增加了代理实例的数量,而不是实际实例,它只有一个。

好像有几种解决方法:

  1. 也用@ApplicationScoped 对@Singleton EJB 进行注解:这有效,每个代理和视图只有一个实例
  2. 用 JNDI 查找替换手动 CDI select:这也有效,只有一个视图实例
  3. 使用 CDI.current.destroy() 删除代理实例:尚未尝试,因为在我们的场景中实现起来并不简单
  4. 将遗留代码也转换为 EJB 或 CDI 管理的 bean,并执行常规的 @Inject:@Singleton EJB 可能仍然需要 @ApplicationScoped?

所以我的问题是:观察是否完全正确,用 EJB @Singleton 和 CDI @ApplicationScoped 注释一个 bean 是否可以,哪个解决方案是首选?

首先,EJB@Singleton不一定翻译成CDI中的@Dependentbean。如果没有添加其他 CDI 范围,这只是 Weld 的默认行为。 以下是 EJB 'maps' 到 CDI 作用域的列表:

  • @Stateless -> @Dependent
  • @Stateful -> @SessionScoped
  • @Singleton -> @Dependent @ApplicationScoped
  • 在焊缝中:
    • @Singleton -> @Dependent(只是在每次注入时创建代理,否则它显然委托给相同的底层 EJB 单例)
    • @Singleton + @ApplicationScoped -> @ApplicationScoped

这是一个 link to spec 描述。

To be able to use it in legacy code not in scope of EJB or CDI, we currently inject it manually using something like CDI.current().select(...).get().

如果我没看错,您可以使用 CDI.current() 从应用程序的不同位置检索此 EJB 单例。现在,这可能会很棘手,因为 CDI.current() 定义不当并试图 "guess" 使用哪个 bean 管理器来检索 bean。如果我们谈论 EAR 部署,这会变得更加棘手。理想情况下,如果可能,您希望避免 CDI.current()

Now we noticed that we have a steadily increasing number of $Proxy$_$$_Weld$EnterpriseProxy$and $$$viewxxx instances of that singleton which I believe ...

在您的情况下,只有 @Singleton 注释,因此代理 CDI 的行为类似于 @Dependent 范围。因此,每次注射都要新注射一次(在您的情况下由 CDI.current() 完成)。但是你正在注入非上下文对象(不是为了简化它而注入到 bean 中)因此你还需要照顾 bean 并在你不再需要它时处理它。

...is it okay to annotate a bean with both EJB @Singleton and CDI @ApplicationScoped

正如您现在所理解的那样,这不仅没问题,这是您经常做的事情吗,因为 @SingletonApplicationScoped 之间的映射看起来比 @Dependent 更自然。 我会说这是解决您问题的首选解决方案。

...so all those manually injected instances live as long as our legacy code class, which is probably just as long as the application lives.

好吧,如果您重复执行该代码并在每个 运行 上重新注入它,那么您的问题就来了。由于遗留代码不是 CDI bean(根据您的说法,它是一个非上下文实例),因此每次都必须创建一个新的代理。您还需要处理相关的 bean 处理 - 与您提出的第三个解决方案类似。