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

36

我有以下配置:

  • 一个包含2个EJB组件的EAR文件,存储在一个GF服务器上。
  • 一个WAR文件,存储在另一个Glassfish服务器上(=>不同JVM),其中包含访问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"注释简单地允许直接调用实现作为"Local" EJB,但您必须像这样在代码中使用实现:

    @Stateless @Local public class ServiceBImpl implements ServiceBItf { @EJB private ServiceAImpl serviceA; ... }

  • 注入一个EJB到另一个EJB的最佳方式是什么? 它的工作方式如下:

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

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

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

但是在GF中它不起作用,我遇到了以下异常:

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

我尝试创建一个本地接口,使用注解“@Inject”进行的依赖注入在两个服务都存在时可以正常工作。

即使我像这样创建本地接口,该服务也无法通过注解“@Inject”进行依赖注入,而是为null:

@Local
public interface ServiceALocalItf {
    ...
}

我阅读了很多文章,高度推荐在本地调用时使用 "@Inject" 而不是 "@EJB"。这引发了我以下的问题:在哪种情况下建议(或仅仅使用)"@Local" EJB 呼叫?

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

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

你认为怎么样?它正确吗?

2个回答

22

你可以看到,我在服务实现上声明了注解 "@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的文档绝对是值得的。

1
首先,感谢您的回答 ;-)对于注解"@Local",我的问题更多是关于没有定义接口的注解"@Local"和注解"@LocalBean"之间的行为差异?结果将是相同的:一个无接口本地bean,不是吗?在我们的情况下,我们真的需要EJB Remote来从前端(在一个服务器上)到后端(在另一个服务器上)进行通信。您所说的"CDI是有状态的"是什么意思?关于生命周期管理?再次感谢您的帮助! - Blaise Gosselin

-1

@Inject注解用于Java Bean(POJOs),而@EJB注解用于企业级Java Bean。当容器将由@EJB注解提供的ejb注入到另一个bean中时,它还控制该ejb的生命周期,为无状态bean执行池化等操作(当要注入的bean未部署时,引用将为空)。如果使用@Inject注解CDI机制,它会像使用new运算符一样查找并创建注入资源的实例(如果要注入的接口的实现不存在,则引用将为空)。您可以使用限定符与@Inject注解一起选择注入接口的不同实现。


1
如果 @Inject 用于 POJO,则它们必须通过引用传递参数,而不像 EJB 通过值传递参数。我说得对吗? - umbr
1
你说的是哪些参数? - maks
1
@Inject注解用于Java Bean(POJOs)中。但这并不完全正确。它也用于EJB和CDI Bean的注入。 - jFrenetic
9
抱歉给你点“踩”的人,但是你的措辞具有误导性,甚至可能是错误的。@Inject不适用于普通Java对象(POJO),而适用于托管Bean(ManagedBean)(JSR 316),并且确实控制其生命周期。托管Bean的实例化与调用new操作符完全不同——你缺少了CDI上下文部分的整个内容(每个托管Bean都驻留在一个上下文中,因此其生命周期与上下文的生命周期绑定)... - Jan Groth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接