本文是《在 Liberty JVM server 中部署 EJB》的后半部分,全系列的目录如下,查看上篇请点击此处。
- 什么是EJB
- 为什么使用EJB
- 技术支持
-
使用会话bean编写业务逻辑
-
使用会话bean管理应用状态
-
使用EJB搭建前端
-
数据完整性
-
跨应用重用EJB
-
安全访问EJB
-
拓展阅读和总结
现在我们有了会话 beans,来看看要怎么使用它们吧。要部署会话 beans,最简单的方法之一就是在 JSF 里,你可以用 EJB in servlets、JSP pages、JAX-RS 应用和其他各种技术。
EJB 可以通过多种方法被注入到其他类中。最简单的是使用 @EJB注解 来注解注入点(injection point),并让容器来管理它。在下面这个例子里,我们把 Catalogue 会话 bean 注入到一个由 JSF 管理的 bean。接着,这个在管理中的 bean 就能在JSF pages 中被直接使用。
package com.ibm.cicsdev.ejb.shop.web;
import java.io.IOException;
import java.util.Collection;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import com.ibm.cicsdev.ejb.CatalogueBean;
import com.ibm.cicsdev.ejb.Item;
@ManagedBean
public class Catalogue
{
@EJB
private CatalogueBean catalogue;
public Collection<Item> getItems() throws IOException {
return this.catalogue.getCatalogue();
}
}
你也可以使用 JNDI API 来查找 EJB。有时这不可避免,尤其是在处理 HTTP 会话状态的时候。我前面提到,EJB 会话和 HTTP 会话是不同的。要通过 HTTP 会话记录一个 stateful session bean,你需要创建一个 HTTP 会话,然后把会话 bean 放进去,比如:
import java.io.IOException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.ibm.cicsdev.ejb.CartBean;
@WebServlet("/cart")
public class CartServlet extends HttpServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
HttpSession session = request.getSession();
if(session.isNew())
{
try
{ CartBean cart =
InitialContext.doLookup("java:global/com.ibm.cicsdev.ejb.app/com.ibm.cicsdev.ejb/CartBean!com.ibm.cicsdev.ejb.CartBean");
session.setAttribute("cart", cart);
}
catch (NamingException e)
{
}
}
CartBean cart = (CartBean) session.getAttribute("cart");
}
}
在加入一个JSF前端后,我们应用的架构现在长这样:
现在用于搭建的砖块已经准备好了,我们可以看看 EJB 容器为应用程序员提供的一些更有用的元素。
在这个部分,我们会研究如何在 EJB 中管理 Java 交易以及 CICS 是如何整合这些交易的。Java EE里的交易是由 JTA 管理的。
在 CICS 中,我们通过 CICS UOW(Unit of Work)整合 JTA 交易。我写过《在 CICS Liberty 中利用 Java 交易协调 JDBC 更新》一文,讨论了 JTA 交易和 CICS 的交互。要了解这个概念,那篇文章是个很好的开始。
EJB 容器提供两种管理 JTA 交易的方法:
-
Bean 管理(bean-managed)
-
容器管理(container-managed)
Bean-managed 交易使得 EJB 可以直接通过 UserTransaction 类来管理 JTA 交易。你接着可以用它来启动、提交或回滚交易,就像在 servlet 里一样(《在 CICS Liberty 中利用 Java 交易协调 JDBC 更新》有更详细的解释)。
import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.ejb.Singleton;
import javax.transaction.UserTransaction;
@Singleton
public class BeanManagedTransactionBean {
@Resource
private SessionContext sessionContext;
public void doTransactionalWork() {
UserTransaction transaction = sessionContext.getUserTransaction();
}
}
Container-managed 交易不和 UserTransaction 类交互。而在 EJB 上,类和方法级别的注解会定义这个类或方法所需交易的形式。方法级别的注解可以覆盖类级别的注解。
下表包括了可以定义的交易行为:
EJB 交易的支持情况(完整版)
Transaction Attribute
(交易特性)
|
No JTA transaction
(无JTA交易)
|
Pre-existing JTA transaction
(已有JTA交易)
|
Mandatory
(强制)
|
返回EJBTransactionRequiredException 异常
|
继承现有的JTA交易
|
Required
(必需)
|
EJB容器创建新的JTA交易
|
继承现有的JTA交易
|
Requires New
(要求新交易)
|
EJB容器创建新的JTA交易
|
返回 javax.ejb.EJBException 异常
|
Supports
(支持)
|
在无JTA交易的情况下继续
|
继承现有的JTA交易
|
Not Supported
(不支持)
|
在无JTA交易的情况下继续
|
挂起JTA交易,但不挂起CICS UOW
|
Never
(绝不)
|
在无JTA交易的情况下继续
|
返回 javax.ejb.EJBException 异常
|
|
有两个交易特性会在 CICS 中受限,这是由 CICS UOWs 运行的方式引起的:
回到我们的例子上来,购买时我们需要调用交易。我们应该根据创建的应用架构来决定选择什么交易特性。
package com.ibm.cicsdev.ejb;
import java.io.IOException;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
@Stateful
public class CartBean
{
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void purchase() throws IOException
{
}
}
在使用 EJB Lite 时,你可以在同一个应用内访问不同 EJB。一般而言,最好是把 EJB 创建为 EAR 应用的一部分;EAR 应用可以包括多个 WAR、EJB JAR 等。使用 EJB 3.2 的话,你可以跨应用访问 EJB,这些应用可以运行在同一个服务器,甚至在不同服务器上。
对我们的例子来说,我们可能还想要一个后台系统来管理库存。为此,我们可以重用 Catalogue EJB,给 bean 添加其他功能,并创建另一个前端。
在我们的范例中,我们已经添加了一个基础的 JAX-RS webservice 来管理库存。即使是这个简单的例子,我们也能轻易重用现有的 EJB。我们还可以更进一步,考虑为我们的店面创建 RESTful API,以便移动手机应用访问。
现在我们需要预防两件事情:其一是防止任何人都可以使用 RESTful webservice 修改库存。其次是要确保我们不会在未经授权的情况下,通过商店偶然暴露以上提到的任何功能。这就是我们接下来要谈到的最后一个话题。
对 EJB 的授权有类和方法的级别。和交易特性一样,如果授权被定义为类的级别,授权适用于对所有方法。如果被定义为方法级别,它能够覆盖任何类级别的授权。
有几种注解可以控制 EJB 的授权,我们可以通过 Java EE 的普通注解(common annotations)来定义 EJB 授权:
-
@DeclareRoles 定义了在本次会话 bean 中使用的 roles
-
@RolesAllow 定义了哪些 Java EE roles 可以访问此方法
-
@DenyAll 禁止任何人调用此方法
-
@PermitAll 允许所有人调用此方法
-
@RunAs 允许事先声明过的特定用户(user ID)访问此方法。这种方式尤其适用于应用程序开发,可以对不同用户设定不同访问权限。
通常而言,保护应用程序最常用的是 @RolesAllow。此外,@DenyAll 和 @PermitAll常用于覆盖或者禁用类级别的安全机制。
和 servlet 一样,如果 CICS region 的安全设置开启的话,Java EE 的用户主体(user principal)会传递到 CICS 交易的用户 ID 上。这使得 CICS 可以执行常规的安全检查,包括交易安全和资源安全检查。但我们应该注意,@RunAs 不会更新 CICS用户 ID,交易会继续运行在最初调用 EJB 的用户之下。
package com.ibm.cicsdev.ejb;
import java.io.IOException;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Singleton;
@Stateless
@DeclareRoles("Administrator")
public class CatalogueBean
{
@RolesAllowed("Administrator")
public Item addStock(int id, int ammount) throws IOException
{
}
}
这些角色和应用中定义的 Java EE 角色以及 Liberty 安全设置映射。在通过 SAF EBJROLE 使用 z/OS 安全功能时,这些 EJBROLE 可以被直接传输到 Java EE 角色中。
EJB 的世界之大,不是三言两语可以穷尽的。这里列出一些有趣的领域,有兴趣的读者可以了解一下:
这篇文章讲述了 EJB 会话 beans 的基础知识:
我们还讨论了在交易和安全上 CICS 和 EJB 是如何整合的。
Knowledge Center for CICS TS 有更多利用 EJB 开发和部署应用的信息,大家可以去看看。
返回上篇
为大家推荐 CICS 爱好者设立的公众号:

扫码关注 “三言两语CICS”
作者:Alexander.D.Brown
译者:陈雅晴
内容声明:本文仅代表作者的个人观点,与IBM立场、策略和观点无关。文中专业名词因翻译原因,表述中难免存在差异。如有疑惑,请以英文为准。同时数据来源于实验室环境,仅供参考。如果您对我们的话题感兴趣,请给我们留言或发邮件。
Tags: 
cics
jvm
ejb
liberty