本文翻译自 Alexander.D.Brown 的博客(EJBs in Liberty JVM server – a Web Shop example),分上下两篇。整个系列目录如下。查看下篇请点击此处。
- 什么是EJB
- 为什么使用EJB
- 技术支持
-
使用会话bean编写业务逻辑
-
使用会话bean管理应用状态
-
使用EJB搭建前端
-
数据完整性
-
跨应用重用EJB
-
安全访问EJB
-
拓展阅读和总结
EJB 是 Java EE(Java Enterprise Edition)的核心部分,我们用它来包含企业应用的业务逻辑。在CICS TS 5.4中,Liberty JVM 服务器支持完整的 EJB 3.2 规范。
这篇 Java 开发者指南会用 EJB 创建了一个简单的在线商店。你可以在 CICS 的 GitHub 上找到完整的 sample code(cics-java-liberty-ejb)。
下图是网络商店示例的结构示意。之后我会详细讲解其中的各个部分。
什么是EJB
EJB 是一个可重用的 Java 类,它包括了一个无参数构造器和用来描述其特性和行为的元数据。EJB 通常用来封装企业级应用的业务逻辑。元数据可以通过类里面的注解来提供,元数据使得类可以被注册(register)到 EJB 容器。元数据也可以通过 XML 描述器文件来提供,有的选项(option)只能被定义在这些描述器里。EJB 容器管理着 EJB 的事务性(transactionality)、安全和生命周期。
为什么使用EJB
EJB 是一个成熟的标准,从早期版本到如今的3.1/3.2规范,EJB 的可用性经历了显著提升。同 CDI(Context and Dependency Injection)和 managed beans 一样,它们都提供了注入框架。而 EJB 还提供了额外的功能,比如异步方法(method)调用、计时器,甚至能够远程调用方法。
注:WebSphere Liberty 支持 EJB Lite 3.1 and EJB 3.2 (包括 EJB Lite 3.2)。
CICS 的 Liberty JVM 服务器对各 CICS 版本或补丁的支持如下:
-
CICS Transaction Server for z/OS 5.4.0 支持 EJB 3.2(包括EJB Lite 3.2)。
-
CICS Transaction Server for z/OS 5.3.0 提供持续交付,通过 APAR PI63877 支持 EJB Lite 3.2。
-
CICS Transaction Server for z/OS 5.3.0 还通过 APAR PI77502 支持 EJB 3.2(包括 EJB Lite 3.2)。
-
CICS Transaction Server for z/OS 5.3.0 和 5.4.0 都支持 EJB Lite 3.1。
EJB 规范定义了两种 beans:
-
会话 beans(Session beans)
-
消息驱动 beans(Message Driven Beans,MDBs)
MDBs 通常需要一个 JMS(Java Messaging Service)的 queue 或者 JCA (Java Connector Architecture) inbound 资源适配器来辅助接受信息。本文主要介绍 session beans。
很多技术都可供使用并和EJB交互。下表列出了其中常见的技术:
规范
|
Java EE 6 特性
|
Java EE 7 特性
|
描述
|
Java Naming and Directory Interface (JNDI)
|
jndi-1.0
|
JNDI 是一种Java API,它让应用程序可以通过给定的名(name)查找数据和对象。JNDI是很多其他Java EE技术的基础,对那些和注入相关的技术尤其很重要。EJB容器把EJB寄存到JNDI名中,让它可以轻松注入到其他类。
|
Java Servlets
|
servlet-3.0
|
servlet-3.1
|
Java servlets 是类,它可以响应请求并模仿服务器行为。它通常用来响应HTTP请求,就像网络服务器一样。Servlets由网络容器运行和管理,能够接收JNDI注入的对象。
|
JavaServer Pages (JSP)
|
jsp-2.1
|
jsf-2.2
|
JSPs是一种服务端技术,用来动态生成网页。页(page)通过一种基于HTML和XML的标记语言定义,并被编译进Servlet。可以使用JavaBeans (只拥有setter 和getter两种方法[methods]的类)来为JSP页中的脚本元素提供支持代码。EJBs可以通过JNDI被注入到JavaBeans。
|
JavaServer Faces (JSF)
|
jsf-2.0
|
jsf-2.2
|
JSF 和JSP类似,但更着眼于Model-View-Controller的设计模式。像JSP一样,JSF页也是由一种基于HTML和XML的标记语言写成的。JSF 页背后由JSF管理的bean支持。和EJB一样,JSF 管理的 bean也是使用注解定义的。JSF管理的bean可以映射到HTTP 会话范围( scope),使操控会话状态更加容易。可以使用JDNI将EJB注入到JSF 管理的beans。
|
Java API for RESTful Web Services (JAX-RS)
|
jaxrs-1.1
|
jaxrs-2.0
|
JAX-RS 是一个用来开发RESTful网络服务的Java API。JAX-RS 应用由一系列定义了RESTful API的类组成。可以通过JNDI将EJB注入到这些类里:我们可以使用 InitialContext 类,或者将这些类定义为EJB,再用@EJB注解将EJB注入。
|
EJB Lite
|
ejbLite-3.1
|
ejbLite-3.2
|
一个 EJB 特性的子集(subset),提供了本地EJB会话bean的基本功能。EJB Lite 3.2还包括非永久计时器和异步方法。
|
EJB Persistent Timers(EJB永续计时器)
|
不支持
|
ejbPersistentTimers-3.2
|
EJB 计时器可以写入数据库做永久保存。
|
Remote EJB method invocation(远程EJB方法调用)
|
不支持
|
ejbRemote-3.2
|
使 EJB 方法可以通过CORBA 被远程调用。
|
EJB home interfaces
|
不支持
|
ejbHome-3.2
|
实现了向前兼容基于EJB 2.X规范编写的EJB
|
EJB
|
不支持
|
ejb-3.2
|
实现了对所有EJB功能的支持(EJB Lite、永久计时器、远程方法调用和home interfaces)。
|
注:使用 WebSphere Liberty 的一大好处是:你可以控制哪种功能处于活跃状态。如果你不需要远程EJB,那么你可以只用EJB Lite特性,这样避免了运行IIOP服务器。
在网络商店的示例中,我们需要加载商店待售商品目录的逻辑。我们可以使用任何加载目录的方法。目录的数据通常存储在数据库甚至是 VSAM 数据集中。通过 JCICS API 可以访问 VSAM 数据,而使用 JDBC 驱动则可以访问 IBM Db2 一类的关系数据库。
在 EJB 中编写业务逻辑的时候,通常会为应用的每一个逻辑部件编写单独的 EJB。这有利于重用和事务语境(transaction context)的分隔等。我们这里的会话 beans 会管理和目录的所有交互:
CatalogueBean.java
package com.ibm.cicsdev.ejb;
import java.io.IOException;
import java.util.List;
import javax.ejb.Stateless;
@Stateless
public class CatalogueBean
{
public List<Item> getCatalogue() throws IOException
{
}
}
高亮的一行(@Stateless 行)把 CatalogueBean 类定义为 EJB 会话 bean。EJB 容器将这个类注册到一个 JNDI 名内。这样这个 bean 就可以被注入到其他类里了,而不需要那些类来创建这个 bean 的实例。在 Liberty 中,JNDI 名需要遵循下面的规定之一:
-
java:global[/application name]/module name/enterprise bean name[!interface name]
-
java:module/enterprise bean name[!interface name]
-
java:app[/module name]/enterprise bean name[!interface name]
当我们把一个 bean 注册到 EJB 容器里时,Liberty 会提供一则消息,显示在
java:global
这个命名空间内 bean 的实际名称:
[6/29/17 15:04:16:019 GMT] 0000003f com.ibm.ws.ejbcontainer.runtime.AbstractEJBRuntime I CNTR0167I: The server is binding the com.ibm.cicsdev.ejb.CatalogueBean interface of the CatalogueBean enterprise bean in the com.ibm.cicsdev.ejb.jar module of the com.ibm.cicsdev.ejb application. The binding location is: java:global/com.ibm.cicsdev.ejb/com.ibm.cicsdev.ejb/CatalogueBean!com.ibm.cicsdev.ejb.CatalogueBean
这个时候我们的架构长这样:
适时记录 web 应用中的状态颇有益处。对我们的网络商店而言,我们想记录购物车的状态。基于不同的需求,会话 bean 提供了三种状态。
-
Singleton session beans(单独会话 bean)在容器中存在一次。每次你注入单独会话bean时,得到的都是同一个对象。
-
Stateless session beans(无状态会话 bean)可以在容器中存在多次。总体而言,容器拥有一个无状态会话bean的池子(pool),所以每次注入可能从池子里再次选择同一个对象,也可能随机选一个全新的对象。
-
Stateful session beans(有状态会话 bean)的生命周期更复杂。不同于 HTTP 会话,每次你注入有状态会话 bean 时,都会得到一个新的对象。这种bean会一直存在于容器中,直到被应用销毁。
容器也可以管理对象的生命周期。
每种 beans 都有两种基本状态:non-existent 和ready。Stateful beans 还有第三种状态:passive。
Singleton session beans 只存在一次,stateless beans(通常)在容器的 pool 里。这让我们能轻松控制这两种 beans 所占用的内存。但容器不能控制 stateful beans 所占的内存,因为应用必须要移除它们。相反,容器可以将 stateful beans 移出内存,进入辅助存储器(secondary storage),使它变成 passive 状态。如果之后需要这个对象,容器可以把 beans 重新放入内存来重启它。

图1. Stateful session bean的生命周期
|
Stateless beans 和 singleton beans 本质上是一样的,它们可以被创建和销毁。Singleton beans 要么在首次注入的时候被创建,要么在应用启动的时候(需要
@Startup
存在)被创建。Stateless beans 经历的生命周期与之类似,只是在 pool 里存在不止一个 bean。

图2. Stateless session bean的生命周期
|
了解了 stateful session beans 的基本概念后,让我们看看购物车范例中一个运行的stateful session bean 吧:
CartBean.java
package com.ibm.cicsdev.ejb;
import java.io.IOException;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
@Stateful
public class CartBean
{
public boolean add(Item item)
{
}
public boolean remove(Item item)
{
}
public List<Item> getItems()
{
}
public boolean purchase() throws IOException
{
}
@Remove
public void clear()
{
}
}
每当我们注入这个类时,都会得到一个全新的实例。这个实例会一直存在,直到我们调用 clear 方法。clear
方法是通过 @Remove 注解定义的,就像上面的代码那样。
现在我们的架构长这样:
转接下篇
作者:Alexander D. Brown
译者:陈雅晴
内容声明:本文仅代表作者的个人观点,与IBM立场、策略和观点无关。文中专业名词因翻译原因,表述中难免存在差异。如有疑惑,请以英文为准。同时数据来源于实验室环境,仅供参考。如果您对我们的话题感兴趣,请给我们留言或发邮件。
Tags: 
cics
jvm
ejb
liberty