Анзор Кармов
第 31 级
Санкт-Петербург

介绍EJB

已在 Random-ZH 群组中发布
在本文中,我们将了解 EJB——Enterprise JavaBeans。该技术是 Java EE 规范的一部分。我们将讨论以下问题:
  • 什么是 EJB;
  • EJB 的历史是什么?
  • 有哪些类型的 EJB?
我们还将使用 EJB 和 servlet 编写一个小型 HelloWorld 应用程序。 EJB 简介 - 1本文对于已经熟悉 Java SE 并开始学习 Java EE 的读者很有用。为了充分理解本文的实践部分,建议您首先阅读“设置本地环境”一文。

EJB 简史

早在 1996 年,当本文作者 5 岁的时候,Java 就已经在开发者中流行起来。其原因是友好的API、自动垃圾收集等。Java被广泛应用于负责后端的系统中。然而,尽管该语言有很多乐趣,但当时的程序员需要 JDK 中尚未实现的某些功能。这些需求是:
  • 确保数据持久性;
  • 交易完整性
  • 竞争性访问数据(多线程控制);
  • 很可能还有别的东西。
所有这些导致本土、自写、封闭图书馆的数量自然增长。换句话说,每个人都尽力满足了自己的需求。直到 IBM 提出了“每个人都应该以同样的方式满足他们的需求”的口号,并于 1997 年发布了 Enterprise Java Bean (EJB) 规范。正是这样,才能够统一开发流程,并将典型问题(上面描述为需求)的解决方案带到框架中。Sun 已经用了两年的时间来适应 IBM 的创意,并于 1999 年发布了 EJB 1.0 规范。这就是该技术的诞生方式,我们将在更多应用方面进一步讨论该技术。

什么是EJB

从某种意义上说,EJB 是一个集体术语,根据上下文,它可以表示一般的 Enterprise JavaBeans 技术本身,也可以表示属于 EJB 技术一部分的某些特定 Enterprise JavaBean 软件组件 (bean)。维基百科上给出了 EJB 作为一种技术的定义:Enterprise JavaBeans(也经常用作缩写 EJB)是一种用于编写和支持包含业务逻辑的服务器组件的技术规范。它是 Java EE 的一部分。当业务逻辑至少需要以下服务之一(通常是所有服务)时,通常使用此技术:
  • 支持数据持久性:即使停止程序后数据也应该是安全的。最常使用数据库来实现;
  • 支持分布式事务;
  • 支持并行数据修改和多线程;
  • 活动支持;
  • 命名和目录支持(JNDI);
  • 数据访问的安全性和限制;
  • 支持在应用服务器上自动安装;
  • 远程访问。
上面列出的服务是EJB技术无疑的优势。另一个这样的优点是上面列出的所有内容都可以立即使用。那些。程序员不需要考虑支持分布式事务。程序员只需要考虑他当前正在尝试实现的业务逻辑。作为特定软件组件的 EJB 是一个 Java 类,带有来自 EJB 规范的一个或多个注释,其中包含应用程序的一些业务逻辑。EJB 规范中的注释赋予了标记类某些权力、权力和超级权力。请阅读下文了解更多相关信息。

EJB类型

我们来总结一下。EJB 是一个带有特殊注释之一的常规 Java 类。这样的类称为 Bean。根据类标记的注释,它将代表一种或另一种类型的 EJB(bean)。豆子主要分为三种类型:
  • Message Driven Beans(消息驱动bean);
  • Entity Beans——在JPA(Java Persistence API)规范中定义,用于存储数据;
  • 会话 Bean。
后者(会话 bean)分为几个子类型:
  • 无状态(无状态);
  • 有状态(支持当前会话状态);
  • 单例(整个应用程序的一个对象;从 EJB 3.1 开始)。
EJB 简介 - 2下面我们将更详细地了解每种类型的 bean。

会话Bean

会话 Bean,或称会话 Bean,是一种特定类型的 Bean。它们封装了客户端可以通过调用 bean 的方法以编程方式调用的业务逻辑。方法调用可以执行以下操作:
  • 本地,通过与会话 bean 相同的 JVM 中的另一个类;
  • 使用 Java RMI(远程方法调用)技术,通过网络从另一个 JVM 进行远程操作。
“会话”一词意味着该 Bean 仅在服务器执行特定任务时可用,并且在服务器发生故障或关闭时将被不可挽回地破坏。会话 bean 实例的生命周期由 EJB 容器控制(您可以在本系列的第一讲中阅读有关 EJB 容器的更多信息)。 无状态会话 Bean不存储有关其状态的信息。这种类型的组件可供各种客户端使用。无状态 Bean 用于实现可在一次操作中完成的业务流程。例如,检查客户的信用记录。因为单个 bean 实例可以由多个客户端使用,所以开发人员必须提供对 bean 数据的线程安全访问。创建这种类型的 Bean(以及所有其他会话 Bean)非常简单。这是一个带有注释的常规 Java 类@Stateless。下面我们举个例子:
import javax.ejb.Stateless;

@Stateless
public class StatelessEjbExample {
    public String sayHi() {
        return "Hi, I'm Stateless EJB!";
    }
}
支持当前会话状态(有状态)的会话 bean保留有关同一客户端调用之间的状态信息,并根据客户端的显式请求终止其存在。这是因为有状态 Bean 对于每个客户端来说都是唯一的。这种类型的 Bean 可以负责的任务的一个示例是使在线商店中的购物车为每个用户保持最新。这些bean 的生命周期由EJB 容器管理。当客户端退出时,这些 Bean 也会被销毁。这样的豆子也很容易创建。这是一个用注释标记的 Java 类Stateful。下面的例子:
import javax.ejb.Stateful;

@Stateful
public class StatefulEjbExample {
    public String sayHi() {
        return "Hi, I,m Stateful EJB";
    }
}
单例会话 bean在应用程序的生命周期内启动一次,并在应用程序的整个生命周期中存在。此类 Bean 专为必须在所有客户端之间共享一种状态的情况而设计。与无状态 Bean 一样,在独立 Bean 中,开发人员需要确保 Bean 具有线程安全的环境。让我们举一个 Singleton bean 的例子,它和上面讨论的对应的 bean 一样容易创建。很容易猜到这是一个带有注释的Java类@Singleton。但是,在这种情况下您需要小心。有两个注释,语法相同,但用途不同并且位于不同的包中:
  • javax.ejb.Singleton
  • javax.inject.Singleton
要创建 EJB,您必须使用javax.ejb. 下面的例子:
import javax.ejb.Singleton;

@Singleton
public class SingletonEjbExample {
    public String sayHi() {
        return "Hi, I'm Singleton EJB!";
    }
}

消息驱动 Bean

消息驱动 Bean(或 MDB)或消息驱动 Bean 实现一些业务逻辑,如会话 Bean。但与它的亲戚不同的是,MDB 有一个重要的区别。客户端从不直接调用 MDB 方法。此类 Bean 通常充当 JMS(Java 消息服务)消息的侦听器,并用于组织系统各部分之间的异步消息交换。此类消息的一个示例是从自动化零售系统向供应管理系统传送库存的请求。下面是 MDB bean 的示例。与会话 bean 不同,它的创建更有趣一些:
import javax.annotation.Resource;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(mappedName = "jms/TestQueue")
public class MessageDrivenEjbExample implements MessageListener {

    @Resource
    private MessageDrivenContext messageDrivenContext;

    public void onMessage(Message message) {
        try {
            if (message instanceof TextMessage) {
                TextMessage msg = (TextMessage) message;
                msg.getText();
            }
        } catch (JMSException e) {
            messageDrivenContext.setRollbackOnly();
        }
    }

}
该注释MessageDriven使我们的 MDB 类成为一个 bean。在注释内部,使用 JNDI(在此处阅读有关 JNDI的信息)确定了 JMS 发行版的名称,我们的类将成为该发行版的侦听器。此外,我们的类还实现了该接口MessageListener及其方法onMessage。当一些消息从队列/分发到达且其名称在注释中定义时,将调用此方法MessageDriven

实体bean

EJB 技术的一部分是 JPA 规范。JPA(即 Java Persistence API)是一种规范,它提供 Java 对象(实体 bean)的对象关系映射 (ORM),并提供用于存储、检索和管理此类对象的 API。JPA 允许您将数据库中的数据表示为 Java 对象,以及将 Java 对象保存为数据库中的记录。并不是每个类都可以充当这样的对象,但实体 bean 除外。Entity Bean 是一个 Java 类,表示数据库中的表。显示(映射)是通过使用特殊注释来实现的。在它们的帮助下,可以将 Java 类与数据库中的表进行比较,以及将 Java 类的字段与数据库表的字段进行比较。下面是一个实体 bean 的示例,代码中带有注释:
@Entity // Делает данный класс Entity бином
@Table(name = "employee") // "Связывает" данный класс с таблицей employee в БД
public class Employee implements Serializable {

    @Id // Говорит о том, что поле ниже является первичным ключом
    @GeneratedValue(strategy = GenerationType.AUTO) // Определяет тип генерации значений первичного ключа
    private int id;

    @Column(name="name") // "Связывает" поле ниже с полем name в таблице employee в БД
    private String name;

    @Column (name="age") // "Связывает" поле ниже с полем age в таблице employee в БД
    private int age;

    // getters and setters...
}
值得注意的是,这种类型的 bean 仅在研究 JPA 规范的背景下才有意义。

编写应用程序:EJB HelloWorld

在本节中,我们将编写一个小型 Java EE HelloWorld 应用程序,并将其部署在 GlassFish 服务器上。在阅读本文之前,强烈建议您阅读有关设置本地环境的文章
  1. 在 IntelliJ IDEA 中创建一个新的 Maven 项目。

    文件 -> 新建 -> 项目...

    EJB 简介 - 3
  2. 点击下一步

  3. 填写Maven项目参数:

    EJB 简介 - 4
  4. 单击“完成”

  5. 该项目已创建并具有以下结构:

    EJB 简介 - 5
pom.xml 文件如下所示: EJB 简介 - 6首先,我们需要添加对 Java EE API 的依赖,并指定以 Web 应用程序存档(war)的形式打包我们的项目。为此,您需要将 pom.xml 代码更改为以下形式:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javarush.lectures</groupId>
    <artifactId>ejb_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
        </dependency>
    </dependencies>

</project>
接下来,您可以继续处理 Java 代码。我们的应用程序将是最简单的。我们将有 1 个 servlet 和 1 个 EJB。这将是一个无状态会话 bean。在 EJB 内部,我们将仅定义 1 个返回字符串“Hello World”的方法。首先,让我们创建一个包com.javarush.lectures。然后,在包内com.javarush.lectures,我们将创建我们的 bean - DemoEJB。bean代码如下:
import javax.ejb.Stateless;

@Stateless
public class DemoEJB {
    public String helloWorld() {
        return "Hello world!";
    }
}
正如前面所说,一切都很简单。我们的下一步是创建一个 servlet,它将传递来自 EJB 的值作为对 HTTP 请求的响应。值得注意的是,servlet 不是本文的主题,但您仍然需要使用它们来演示 EJB。为此,我们DemoServlet在与 EJB 相同的包中创建一个新的 servlet。其代码如下:
@WebServlet("/helloWorld")
public class DemoServlet extends HttpServlet {

    @EJB
    private DemoEJB ejb;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write(ejb.helloWorld());
    }
}
以下是对代码的一些简短评论。Abstract @WebServlet("/helloWorld")- 将我们的类定义为 servlet,它将处理对端点的 HTTP 请求/helloWorld。我们班有一个场地—— DemoEJB ejb. 这是我们之前定义的 bean。类字段上的注释 —@EJB执行依赖项注入 (DI)。那些。需要时,ejb 变量会自动用新实例进行初始化。我们的类是 HttpServlet 的后代,并重写超类方法之一 - doGet。此方法处理 HTTP GET 请求并采用两个参数 -HttpServletRequestHttpServletResponseHttpServletRequest用于获取有关传入 HTTP 请求的信息。HttpServletResponse需要生成对请求的响应。在方法内部,我们使用PrintWriter.response 对象从响应对象 ( ) 获取对象。接下来,我们可以使用 向结果对象写入一些值。事实上,我们通过将从我们定义的 EJB 获得的值写入 -a 对象来使用它(该值是字符串“Hello World!”)。发送 HTTP 请求的客户端将收到此值作为对其请求的响应。下一步是在 GlassFish Java EE 服务器上启动应用程序。为此,我们将创建一个新配置,如有关设置本地环境的文章中所述。下面是当前项目完成配置的屏幕截图。确保在开始之前安装了 GlassFish 服务器: 创建启动配置后,使用Run -> Run 'ejb_demo'菜单或使用Shift+F10热键启动应用程序。启动后,您可以看到它的日志: 以及打开的浏览器: 所有这些都表明应用程序按预期工作。 HttpServletResponsegetWriter()writePrintWriterEJB 简介 - 7EJB 简介 - 8EJB 简介 - 9

结论

在本文中,我们了解了 EJB——Enterprise JavaBeans。我们考虑了以下问题:
  • 什么是EJB?
  • EJB历史
  • 不同类型的 EJB
回想一下,EJB 有以下类型:
  • Message Driven Beans(消息驱动bean);
  • Entity Beans - 在JPA(Java Persistence API)实体规范中定义并用于存储数据;
  • 会话 Bean:
    • 无状态(无状态)
    • 有状态(支持当前会话状态)
    • 单例(整个应用程序的一个对象;从 EJB 3.1 开始)
我们还使用 EJB 编写了一个小型 HelloWorld 应用程序。作为PD,您可以自己重复本文的实践部分。然后再向您的应用程序添加两个 servlet,它们将使用有状态 bean 和单例 bean 来接收值。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION