无论你创建bean会话是为了执行特定任务,还是把表映射到实体bean以更新数据,都可以使用普通的java对象和接口来完成这些工作,并且可以通过在业务方法中使用注释,把方法提供给客户端。
enterprise javabean (ejb) 是可重用的、可移植的 j2ee 组件。ejb 由封装业务逻辑的方法组成。譬如说,ejb 可能有这样的业务逻辑:包含了更新数据库中客户数据的方法。众多远程和本地客户端可以调用该方法。另外,ejb 在容器里面运行,这样开发人员只要关注bean里面的业务逻辑,不必担心复杂、容易出错的问题,譬如事务支持、安全性和远程对象访问等。ejb 作为普通java对象(pojo)的形式来开发,开发人员可以使用元数据注释(metadata annotations)来指定容器如何管理这些bean。
ejb 包括三种主要类型:会话 bean、实体 bean和消息驱动的bean。会话bean执行独立的、解除耦合的任务,譬如检查客户的信用记录。实体bean是一个复杂的业务实体,它代表数据库中存在的业务对象。消息驱动的bean用于接收异步jms 消息。下面,让我们进一步研究ejb 3.0规范中的这些类型。
一、会话bean
会话bean通常代表业务流程里面的操作,譬如“处理订单”。可根据对话状态的保持性,即有状态和无状态对会话bean进行分类。
无状态的会话 bean没有内部状态。它们不跟踪记录从一个方法调用传递到另一个方法调用的信息。因此,每次调用无状态的业务方法都独立于前一次调用,譬如计算税款或者运费。用某个应税值调用计算税款的方法时,对税款值进行计算并返回给调用方法,而不必保存调用者的内部状态供以后调用。因为这些bean并不保持状态,所以容器对它们进行管理就很简单。客户端请求无状态的bean实例时,可以从容器保持的无状态的会话bean 实例池当中接收一个实例。另外,因为无状态的会话 bean可以共享,所以容器可保持数量较少的实例为许多客户端提供服务。想指定java bean作为无状态的会话bean加以部署及管理,只需要为该bean添加注释@stateless。
有状态的会话 bean在方法调用时可保持对话状态,譬如客户的网上购物车。客户开始网上购物时,可以从数据库中检索客户的详细信息。客户往购物车里面添加商品或者从里面删除商品、下订单等时调用的其他方法也可以使用这些详细信息。不过,有状态的会话bean是暂时性的,因为出现会话终止、系统崩溃或者网络故障后,状态不复存在。客户端请求有状态的会话bean实例时,就为该客户端分配一个有状态的实例,并为该客户端保持该组件的状态。要指定容器在某个方法完成后删除有状态的会话bean实例,只要为该方法添加注释@remove。
会话 bean示例如下:
import javax.ejb.stateless.*;
/*a simple stateless session bean implementing the incrementvalue() method of the * calculateejb interface.*/
@stateless(name="calculateejb")
public class calculateejbbean
implements calculateejb
{
int value = 0;
public string incrementvalue()
{
value++;
return "value incremented by 1";
}
}
二、实体bean
实体bean是管理持久性数据的一个对象,有可能使用几个相关的java对象,并可以通过主键实现惟一性。通过添加@entity注释,可以把某类指定为实体bean。实体bean代表数据库中的持久性数据,如客户表中的一行或者员工表中的一条员工记录。实体bean还可以在多个客户端之间共享。譬如说,某个员工实体bean可以由多个客户端用于计算某员工的年薪或者更新员工地址。实体bean对象的特定字段可以成为持久性字段。实体bean中没有被@transient注释标记的所有字段都被视为持久性字段。ejb 3.0的一个主要特性就是,能够使用元数据注释来创建包含对象/关系映射的实体bean。譬如说,想指定把实体bean的empid字段映射到 employees表中的empno属性,就要使用@table(name="employees") 来注释表名,使用 @column(name="empno") 来注释字段,如下面的例子所示。另外,ejb 3.0 的一个特性是,在开发期间可以方便地测试实体bean,因为现在使用 oracle 应用服务器实体测试工具,就可以在容器外面运行实体bean。
实体 bean示例如下:
import javax.persistence.*;
import java.util.arraylist;
import java.util.collection;
@entity
@table(name = "employees")
public class employee implements java.io.serializable
{
private int empid;
private string ename;
private double sal;
@id
@column(name="empno", primarykey=true)
public int getempid()
{ return empid;}
public void setempid(int empid)
{ this.empid = empid; }
public string getename()
{ return ename; }
public void setename(string ename)
{ this.ename = ename; }
public double getsal()
{ return sal; }
public void setsal(double sal)
{ this.sal = sal; }
public string tostring()
{stringbuffer buf = new stringbuffer();
buf.append("class:")
.append(this.getclass().getname()).append(" ::") .append(" empid:").append(getempid()).append(" ename:") .append(getename()).append("sal:").append(getsal());
return buf.tostring();}
}
三、消息驱动的bean
消息驱动的bean(mdb)为实现异步通信提供了一种比使用直接的java消息服务(jms)更简单的方法。mdb用于接收异步jms消息。容器处理jms队列和主题所需的大部分设置进程。它把所有消息发送给相关的mdb。mdb允许j2ee应用程序发送异步消息,随后这些消息由应用程序来处理。要把bean指定为mdb,需要实现javax.jms.messagelistener接口,并且用@messagedriven注释该bean。
消息驱动的bean示例如下:
import javax.ejb.messagedriven;
import javax.ejb.activationconfigproperty;
import javax.ejb.inject;
import javax.jms.*;
import java.util.*;
import javax.ejb.timedobject;
import javax.ejb.timer;
import javax.ejb.timerservice;
@messagedriven(
activationconfig = {
@activationconfigproperty(propertyname="connectionfactoryjndiname",
propertyvalue="jms/topicconnectionfactory"),
@activationconfigproperty(propertyname= "destinationname", propertyvalue="jms/mytopic"),
@activationconfigproperty(propertyname= "destinationtype", propertyvalue="javax.jms.topic"),
@activationconfigproperty(propertyname= "messageselector", propertyvalue="recipient = 'mdb'") } )
/** a simple message-driven bean that listens to the configured jms queue or topic and gets notified via an * invocation of it's onmessage() method when a message has been posted to the queue or topic.the bean
* prints the contents of the message. */
public class messagelogger implements messagelistener, timedobject
{
@inject javax.ejb.messagedrivencontext mc;
public void onmessage(message message)
{ system.out.println("onmessage() - " + message);
try
{
string subject = message.getstringproperty("subject");
string inmessage = message.getstringproperty("message");
system.out.println("message received/n/tdate:" + new java.util.date() + "/n/tsubject:" + subject + "/n/tmessage:" + inmessage + "/n");
system.out.println("creating timer a single event timer");
timerservice ts = mc.gettimerservice();
timer timer = ts.createtimer(30000, subject);
system.out.println("timer created by mdb at:" + new date(system.currenttimemillis()) +" with info:"+subject); }
catch (throwable ex)
{ ex.printstacktrace(); }
}
public void ejbtimeout(timer timer)
{ system.out.println("ejb 3.0:timer with mdb");
system.out.println("ejbtimeout() called at:" + new date(system.currenttimemillis()));
return; }
}
四、使用 ejb 3.0
ejb客户端是访问bean的应用程序。它不必位于客户端层上,但可以是独立的应用程序、java服务器页面(jsp)、服务器小程序或者另一个ejb。客户端通过bean的远程或本地接口来使用ejb的方法,远程还是本地取决于客户端是在同一个jvm里面还是不同的jvm里面。这些接口定义了bean的方法,而bean类负责实际实现这些方法。客户端访问bean类的方法时,容器就会为bean生成一个代理,名为远程或者本地对象。远程或者本地对象接收请求后,交给相应的bean实例,并将结果返回给客户端。想调用bean的方法,客户端需要通过使用ejb部署描述符(deployment descriptor)里面定义的bean名称来找到该bean。在以下的示例中,客户端使用context对象找到名为“statelessejb”的bean。
ejb 客户端示例如下:
import javax.naming.context;
import javax.naming.initialcontext;
/* a simple bean client which calls methods on a stateless session bean.*/
public class calculateejbclient
{
public static void main(string [] args)
{
context context = new initialcontext();
calculateejb myejb =(calculateejb)context.lookup ("java:comp/env/ejb/calculateejb");
myejb.incrementvalue(); }
}
链接:程序员应用ejb 3.0必要的准备
闽公网安备 35060202000074号