@Inject、@EJB、@Local、@Remote、@LocalBean等:困惑?

2022-09-01 06:15:16

我有以下配置:

  • 一个 GF 上的 1 个 EAR,其中包含 2 个带有 EJB 组件的 EJB-JAR。
  • 1 另一台 Glassfish 服务器(=>其他 JVM)上的 WAR,其中包含访问 EJB 组件的 Web 组件。

我在 EAR 的每个 EJB-JAR 中都有 2 个 EJB 业务服务,它们都是这样开发的:

@Remote
public interface ServiceAItf {
    ...
}

@Stateless
@Local
public class ServiceAImpl implements ServiceAItf {
    ...
}

在我的 WAR 中,我通过远程接口上的显式“InitialContext.lookup”访问 EJB 组件。

在我的EAR中,我对注入的最佳实践感到非常困惑,在性能,体系结构等方面...

我有以下问题:

  • 如您所见,我已经在服务实现上声明了注释“@Local”,而没有定义本地接口。这是正确的吗?至少我在部署时没有错误。但也许我应该使用“@LocalBean”注释来代替?我假设“@LocalBean”注释只是允许直接调用实现作为“本地”EJB,但是您必须在代码中使用实现,如下所示:

    @Stateless @Local公共类 ServiceBImpl 实现 ServiceBItf { @EJB private ServiceAImpl serviceA; ... }

  • 将一个 EJB 注入另一个 EJB 的最佳方法是什么?它的工作原理如下:

    @Stateless @Local公共类 ServiceBImpl 实现 ServiceBItf { @EJB private ServiceAItf serviceA; ... }

但从我注意到的情况来看,注入的“serviceA”是远程代理,而它位于同一EAR文件的同一JVM中。因此,我认为会对性能产生影响。这就是为什么我试图像这样注入服务:

@Stateless
@Local
public class ServiceBImpl implements ServiceBItf {
    @Inject
    private ServiceAItf serviceA;
    ...
}

但它在GF中不起作用,我有以下例外:

WELD-001408 Unsatisfied dependencies for type [...] ...

然后,我尝试创建一个本地接口,当两个服务都有效时,通过注释“@Inject”进行注入。

即使我创建了这样的本地接口,该服务也不会通过注释“@Inject”注入,而是空的:

@Local
public interface ServiceALocalItf {
    ...
}

我读过很多文章,强烈建议在本地调用时使用“@Inject”而不是“@EJB”。这就引出了以下问题:在这种情况下,建议(或直接使用)“@Local”EJB 调用?

经过所有这些分析,我得出以下结论:

  • 对于每个服务,我创建一个“@Local”一个“@Remote”接口。
  • 从 WAR 到 EAR 的 EJB-JAR,对远程接口进行 JNDI 查找。
  • 从 EJB-JAR 到 EJB-JAR,通过“@EJB”注入到本地接口。
  • 对于同一 EJB-JAR 中的两个服务,通过“@Inject”注入到本地接口。

对此,你怎么看?这是正确的吗?


答案 1

如您所见,我已经在服务实现上声明了注释“@Local”,而没有定义本地接口。这是正确的吗?

在 EJB 3.1 中,对本地接口的要求已被删除。除非您明确需要它们,否则无需编写它们。

将一个 EJB 注入另一个 EJB 的最佳方法是什么?

这里要写的几件事:

随着Java EE 6的出现,Java Enterprise发生了变化。新的 JSR 将所谓的受管 Bean(不要与 JSF 受管 Bean 混淆)定义为一种最小组件,在依赖关系注入和生命周期管理方面仍然可以从容器中受益。这意味着:如果你有一个组件,并且“只是”想要使用DI并让容器控制其生命周期,那么你不需要为它使用EJB。当且仅当您明确需要 EJB 功能(如事务处理、池化、钝化和集群)时,您最终将使用 EJB。

这使得您的问题的答案分为三个部分:

  1. 使用@Inject@EJB,CDI的概念(a)适用于所有托管bean(包括EJB)和(b)是有状态的,因此远远优于纯@EJB DI
  2. 您确定您的组件需要 EJB 吗?
  3. 绝对值得一看 CDI 文档

答案 2

@Injectannotation 用于 java bean(POJO),而 annotation 用于企业 java bean。当一个容器将注释提供的 ejb 注入到另一个 bean 时,它还控制该 ejb 的生命周期,对无状态 Bean 执行池化等(当将要注入的 Bean 未部署时,引用将为 null)。如果您使用注释CDI机制,只需查找并创建注入资源的实例,例如使用new运算符(如果要注入的接口的实现不存在,则引用将为null)。您可以将限定符与注释结合使用,以选择注入接口的不同实现。@EJB@EJB@Inject@Inject


推荐