基本的EJB参考,注入和查找

在本系列的第一部分中 ,我们介绍了Enterprise JavaBeans v。3.0规范提供的机制,用于定义EJB组件,声明对EJB的引用并通过依赖项注入或程序化JNDI查找将它们连接起来。

在此博客文章中,我们将研究一些基本示例以了解如何使用EJB API。

基本EJB

EJB本质上是带有一些额外EJB元数据的POJO。 可以通过使用EJB批注或通过标准部署描述符来提供将其部署为EJB组件所需的元数据。 以下类实现了一个非常基本的无状态会话EJB:

package es.reacts;

import javax.ejb.Stateless;

@Stateless(name = "UniqueLocalSessionEJB")
public class UniqueLocalSessionEJBBean implements UniqueLocalBusinessInterface {
   public UniqueLocalSessionEJBBean() {
   }

   public String sayLocalHello() {
    return this.getClass().getName() + "::" + "Local hello.";
   }
}

正如您可能从我们以前的博客文章中所回顾的那样, @Stateless批注用于定义无状态会话bean。 可选的name元素用于定义会话bean 名称 。 该元素类似于标准部署描述符的<ejb-name />元素。 此元素默认为bean类(UniqueLocalSessionEJBBean在上面的例子中),和上述使用它的示例的非限定名称重新命名bean来UniqueLocalSessionEJB。

由于我们使用@Stateless批注,因此不再需要在部署描述符中声明EJB。

在此示例中,我们假设EJB打包在EJB模块中,该模块取决于包含其业务接口定义的模块(如以下部分所述)。

业务接口

每个EJB都实现一个或多个业务接口。 业务接口可以是本地远程的 。 两种类型的业务接口之间最重要的区别可以归纳如下:

  • 本地业务接口对其方法使用按引用传递语义,并且方法调用不能跨越JVM边界。 本地业务接口仅对被调用方的相同应用程序和JVM实例中的调用方可用。
  • 远程业务接口对其方法使用按值传递语义,并且方法调用可以跨越JVM边界。 远程业务接口可用于被呼叫者应用程序之外的呼叫者。

在前面的示例中,业务接口UniqueLocalBusinessInterface声明如下:

package es.reacts;

import javax.ejb.Local;

@Local
public interface UniqueLocalBusinessInterface {
   String sayLocalHello();
}

在EJB v。3.0世界中,业务接口只是用@Local@Remote批注进行批注的普通Java接口。

包装业务接口

在此示例中,我们假设EJB业务接口打包在EJB模块依赖的JAR文件中。 由于EJB客户端仅依赖EJB业务接口,因此,将业务接口打包在一个单独的库中是一个好习惯,以简化接口分配并使它们与实现分离。

将EJB注入Java Servlet

既然我们已经定义了EJB,就可以在Java EE Web模块中的servlet中使用它了。 假设在我们的应用程序中只有一个EJB实现了UniqueLocalBusinessInterface ,我们可以使用空的@EJB注释将其注入:

package es.reacts;

import java.io.IOException;
import java.io.PrintWriter;

import javax.ejb.EJB;

import javax.servlet.*;
import javax.servlet.http.*;

public class ServletTest1 extends HttpServlet {
  @EJB
  UniqueLocalBusinessInterface lc;

  public void doGet(HttpServletRequest request,
   HttpServletResponse response)
   throws ServletException, IOException {
   [...]
   lc.sayLocalHello();
   [...]
  }

首先要注意的是,由于仅bean接口就足以识别目标EJB,因此应用服务器将EJB注入了EJB。 在这种情况下,@EJB批注的beanInterface元件取它的默认值,因为在我们解释之前的帖子 UniqueLocalBusinessInterface:,那是注入字段的类型。 由于应用程序中只有一个EJB可以实现此业务接口,因此servlet的lc字段将注入对此类实例的引用。

值得指出的第二件事是,由于EJB是无状态的 ,因此我们正在将EJB安全地注入到servlet字段中。 由于servlet的默认情况下无状态的 ,你应该注射状态的资源转换成Servlet时域特性,否则你可能会碰到并发相关的问题。 如果需要在Servlet中使用有状态EJB,则应通过程序化JNDI查找来检索引用,因为这将确保每次查找操作都返回一个新实例。

让我们部署并运行我们的应用程序,我们将看到servlet注入了它的目标EJB,并且正确执行了对其业务接口的sayLocalHello()方法的方法调用。

如果我们想注入对远程接口的引用,则客户端代码不会受到影响。 如果尝试将UniqueLocalBusinessInterface@Local更改为@Remote ,那么您会看到该servlet没有任何变化,并且可以继续正常工作。

如果一个以上的EJB实现相同的接口会发生什么?

假设我们在此应用程序的EJB模块中添加了另一个EJB,它实现了与上一个相同的接口UniqueLocalBusinessInterface 。 在这种情况下,由于bean接口不再足以确定要注入的目标bean,因此将返回一个错误。 例如,在WebLogic Application Server中部署这样的应用程序会导致引发以下错误:

[08:46:25 PM] Caused by: weblogic.deployment.EnvironmentException: [J2EE:160199]Error resolving ejb-ref 'es.reacts.ServletTest1/lc1' from module 'WebTest0' of application 'EJBTestApp'. The ejb-ref does not have an ejb-link and the JNDI name of the target bean has not been specified. Attempts to automatically link the ejb-ref to its target bean failed because multiple EJBs in the application were found to implement the 'es.reacts.UniqueLocalBusinessInterface' interface. Please specify a qualified ejb-link for this ejb-ref to indicate which EJB is the target of this ejb-ref.

注入对特定EJB实例的引用

为了解决上一节中出现的问题,我们需要为应用程序服务器提供所需的信息,以标识目标EJB。 如前一篇文章所述 ,我们可以使用以下两种方法:

  • 我们可以使用@EJB批注的name元素(或部署描述符的相应<ejb-ref-name />元素)在应用程序的私有名称空间中声明EJB引用,然后使用EJB链接到目标bean。部署描述符。
  • 或者,我们使用@EJB批注的beanName元素(或部署描述符的相应<ejb-link />元素)直接在我们的代码中进行操作。

将EJB映射到私有命名空间

使用第一种方法,我们将在servlet中获得以下代码:

@EJB(name = "ejb/bean-name")
UniqueLocalBusinessInterface lc;

以及充当EJB客户端的Java EE Web模块的部署描述符(web.xml)中的以下元素:

<ejb-local-ref>
  <ejb-ref-name>ejb/bean-name</ejb-ref-name>
  <ejb-ref-type>Session</ejb-ref-type>
  <local>es.reacts.UniqueLocalBusinessInterface</local>
  <ejb-link>UniqueLocalSessionEJB</ejb-link>
</ejb-local-ref>

<ejb-link />元素包含我们在示例开头定义的带注释的Bean名称:

@Stateless(name = "UniqueLocalSessionEJB")

在EJB实现类中。

请注意,在此示例中,我们显式使用了@EJB name元素,但是我们可以使用其默认值来建立链接。 name元素的默认值为:

[合格的类名称] / [属性或字段名称]

在这种情况下,将是:

es.reacts.ServletTest1 / lc

使用默认的自动生成的名称以及使用<ejb-link />进行EJB链接的缺点是,每次重构代码时,都必须检查部署描述符。 尽管开发人员有时会另外考虑,但Java EE规范定义了一些其他角色,例如,攻击者和部署者。 在大型公司环境中,此类概要文件会覆盖开发人员的注释以“插入”应用程序使用的组件并不少见。 注释覆盖是标准部署描述符仍然存在的原因之一。 当引用是在应用程序内部或外部的远程组件时,尤其如此。 为此,我建议你不要依赖于自动生成的名称,并使用自定义的有据可查的名称代替。

将EJB链接到私有命名空间中的引用

第二种方法提供了使用@EJB批注的beanName元素将引用链接到其目标bean的直接方法。 Servlet代码将使用以下EJB参考:

@EJB(beanName = "UniqueLocalSessionEJB")
UniqueLocalBusinessInterface lc;

并且我们不需要部署描述符中的其他信息。

尽管此方法允许开发人员在不依赖部署描述符的情况下将引用链接到EJB,但是上一节末尾给出的建议仍然有效。 请记住,可以在部署时覆盖注释! 如果事先知道这样的引用可以覆盖,则不要将EJB链接到引用。 在这种情况下,最好为引用指定一个名称,如上一节所述。

参考: The Gray Blog上的JCG合作伙伴 Gray提供了基本的EJB参考,注入和查找

相关文章 :

翻译自: https://www.javacodegeeks.com/2011/08/basic-ejb-references-injection-and.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值