來源:
http://java.chinaitlab.com/EJB/356299.html
無論你唇╞ean會(huì)話是為了執(zhí)行特定任務(wù),還是把表映射到實(shí)體bean以更新數(shù)據(jù),都可以使用普通的
Java對(duì)象和接口來完成這些工作,并且可以通過在業(yè)務(wù)方法中使用注釋,把方法提供給客戶端。
Enterprise JavaBean (EJB) 是可重用的、可移植的 J2EE 組件。EJB 由封裝業(yè)務(wù)邏輯的方法組成。譬如說,EJB 可能有這樣的業(yè)務(wù)邏輯:包含了更新數(shù)據(jù)庫中客戶數(shù)據(jù)的方法。眾多遠(yuǎn)程和本地客戶端可以調(diào)用該方法。另外,EJB 在容器里面運(yùn)行,這樣開發(fā)人員只要關(guān)注bean里面的業(yè)務(wù)邏輯,不必?fù)?dān)心復(fù)雜、容易出錯(cuò)的問題,譬如事務(wù)支持、安全性和遠(yuǎn)程對(duì)象訪問等。EJB 作為普通Java對(duì)象(POJO)的形式來開發(fā),開發(fā)人員可以使用元數(shù)據(jù)注釋(metadata annotations)來指定容器如何管理這些bean。
EJB 包括三種主要類型:會(huì)話 bean、實(shí)體 bean和消息驅(qū)動(dòng)的bean。會(huì)話bean執(zhí)行獨(dú)立的、解除耦合的任務(wù),譬如檢查客戶的信用記錄。實(shí)體bean是一個(gè)復(fù)雜的業(yè)務(wù)實(shí)體,它代表數(shù)據(jù)庫中存在的業(yè)務(wù)對(duì)象。消息驅(qū)動(dòng)的bean用于接收異步JMS 消息。下面,讓我們進(jìn)一步研究EJB 3.0規(guī)范中的這些類型。
一、會(huì)話bean
會(huì)話bean通常代表業(yè)務(wù)流程里面的操作,譬如“處理訂單”。可根據(jù)對(duì)話狀態(tài)的保持性,即有狀態(tài)和無狀態(tài)對(duì)會(huì)話bean進(jìn)行分類。
無狀態(tài)的會(huì)話 bean沒有內(nèi)部狀態(tài)。它們不跟蹤記錄從一個(gè)方法調(diào)用傳遞到另一個(gè)方法調(diào)用的信息。因此,每次調(diào)用無狀態(tài)的業(yè)務(wù)方法都獨(dú)立于前一次調(diào)用,譬如計(jì)算稅款或者運(yùn)費(fèi)。用某個(gè)應(yīng)稅值調(diào)用計(jì)算稅款的方法時(shí),對(duì)稅款值進(jìn)行計(jì)算并返回給調(diào)用方法,而不必保存調(diào)用者的內(nèi)部狀態(tài)供以后調(diào)用。因?yàn)檫@些bean并不保持狀態(tài),所以容器對(duì)它們進(jìn)行管理就很簡(jiǎn)單。客戶端請(qǐng)求無狀態(tài)的bean實(shí)例時(shí),可以從容器保持的無狀態(tài)的會(huì)話bean 實(shí)例池當(dāng)中接收一個(gè)實(shí)例。另外,因?yàn)闊o狀態(tài)的會(huì)話 bean可以共享,所以容器可保持?jǐn)?shù)量較少的實(shí)例為許多客戶端提供服務(wù)。想指定Java Bean作為無狀態(tài)的會(huì)話bean加以部署及管理,只需要為該bean添加注釋@Stateless。
有狀態(tài)的會(huì)話 bean在方法調(diào)用時(shí)可保持對(duì)話狀態(tài),譬如客戶的網(wǎng)上購物車。客戶開始網(wǎng)上購物時(shí),可以從數(shù)據(jù)庫中檢索客戶的詳細(xì)信息。客戶往購物車?yán)锩嫣砑由唐坊蛘邚睦锩鎰h除商品、下訂單等時(shí)調(diào)用的其他方法也可以使用這些詳細(xì)信息。不過,有狀態(tài)的會(huì)話bean是暫時(shí)性的,因?yàn)槌霈F(xiàn)會(huì)話終止、系統(tǒng)崩潰或者網(wǎng)絡(luò)故障后,狀態(tài)不復(fù)存在。客戶端請(qǐng)求有狀態(tài)的會(huì)話bean實(shí)例時(shí),就為該客戶端分配一個(gè)有狀態(tài)的實(shí)例,并為該客戶端保持該組件的狀態(tài)。要指定容器在某個(gè)方法完成后刪除有狀態(tài)的會(huì)話bean實(shí)例,只要為該方法添加注釋@Remove。
會(huì)話 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";
}
}
二、實(shí)體bean
實(shí)體bean是管理持久性數(shù)據(jù)的一個(gè)對(duì)象,有可能使用幾個(gè)相關(guān)的Java對(duì)象,并可以通過主鍵實(shí)現(xiàn)惟一性。通過添加@Entity注釋,可以把某類指定為實(shí)體bean。實(shí)體bean代表數(shù)據(jù)庫中的持久性數(shù)據(jù),如客戶表中的一行或者員工表中的一條員工記錄。實(shí)體bean還可以在多個(gè)客戶端之間共享。譬如說,某個(gè)員工實(shí)體bean可以由多個(gè)客戶端用于計(jì)算某員工的年薪或者更新員工地址。實(shí)體bean對(duì)象的特定字段可以成為持久性字段。實(shí)體bean中沒有被@Transient注釋標(biāo)記的所有字段都被視為持久性字段。EJB 3.0的一個(gè)主要特性就是,能夠使用元數(shù)據(jù)注釋來創(chuàng)建包含對(duì)象/關(guān)系映射的實(shí)體bean。譬如說,想指定把實(shí)體bean的empId字段映射到 Employees表中的EMPNO屬性,就要使用@Table(name="Employees") 來注釋表名,使用 @Column(name="EMPNO") 來注釋字段,如下面的例子所示。另外,EJB 3.0 的一個(gè)特性是,在開發(fā)期間可以方便地測(cè)試實(shí)體bean,因?yàn)楝F(xiàn)在使用 Oracle 應(yīng)用服務(wù)器實(shí)體測(cè)試工具,就可以在容器外面運(yùn)行實(shí)體bean。
實(shí)體 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();}
}
三、消息驅(qū)動(dòng)的bean
消息驅(qū)動(dòng)的bean(MDB)為實(shí)現(xiàn)異步通信提供了一種比使用直接的Java消息服務(wù)(JMS)更簡(jiǎn)單的方法。MDB用于接收異步JMS消息。容器處理JMS隊(duì)列和主題所需的大部分設(shè)置進(jìn)程。它把所有消息發(fā)送給相關(guān)的MDB。MDB允許J2EE應(yīng)用程序發(fā)送異步消息,隨后這些消息由應(yīng)用程序來處理。要把bean指定為MDB,需要實(shí)現(xiàn)javax.jms.MessageListener接口,并且用@MessageDriven注釋該bean。
消息驅(qū)動(dòng)的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的應(yīng)用程序。它不必位于客戶端層上,但可以是獨(dú)立的應(yīng)用程序、Java服務(wù)器頁面(JSP)、服務(wù)器小程序或者另一個(gè)EJB。客戶端通過bean的遠(yuǎn)程或本地接口來使用EJB的方法,遠(yuǎn)程還是本地取決于客戶端是在同一個(gè)JVM里面還是不同的JVM里面。這些接口定義了bean的方法,而bean類負(fù)責(zé)實(shí)際實(shí)現(xiàn)這些方法。客戶端訪問bean類的方法時(shí),容器就會(huì)為bean生成一個(gè)代理,名為遠(yuǎn)程或者本地對(duì)象。遠(yuǎn)程或者本地對(duì)象接收請(qǐng)求后,交給相應(yīng)的bean實(shí)例,并將結(jié)果返回給客戶端。想調(diào)用bean的方法,客戶端需要通過使用EJB部署描述符(deployment descriptor)里面定義的bean名稱來找到該bean。在以下的示例中,客戶端使用Context對(duì)象找到名為“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(); }
}
posted on 2009-02-27 14:35
ID刀 閱讀(334)
評(píng)論(0) 編輯 收藏 所屬分類:
JAVA_Base