EJB3.0規(guī)范使開發(fā)EJB比過去更容易,可能誘惑你考慮開發(fā)***個EJB。如果真是這種情況,那么祝賀你,你經(jīng)成功避免了在你以前EJB開發(fā)者的很多挫折,并且享受到EJB3.0開發(fā)的便利性。但是你開始開發(fā)以前,你可能想知道EJB是什么和它們用于什么目的。本篇文章解釋了EJB的基礎(chǔ)和你如何在一個J2EE程序中使用
它們。
什么是EJB?
一個企業(yè)JavaBean (EJB)是一個可重用的,可移植的J2EE組件。 EJB由封裝了業(yè)務(wù)邏輯的多個方法組成。例如,一個EJB可以有包括一個更新客戶數(shù)據(jù)庫中數(shù)據(jù)的方法的業(yè)務(wù)邏輯。多個遠(yuǎn)程和本地客戶端可以調(diào)用這個方法。另外,EJB運行在一個容器里,允許開發(fā)者只關(guān)注與bean中的業(yè)務(wù)邏輯而不用考慮象事務(wù)支持,安全性和遠(yuǎn)程對象訪問等復(fù)雜和容易出錯的事情。EJB以POJO或者普通舊的Java對象形式開發(fā),開發(fā)者可以用元數(shù)據(jù)注釋來定義容器如何管理這些Bean。
EJB類型
EJB主要有三種類型:會話Bean,實體Bean和消息驅(qū)動Bean。會話Bean完成一個清晰的解耦的任務(wù),例如檢查客戶賬戶歷史記錄。實體Bean是一個代表存在于數(shù)據(jù)庫中業(yè)務(wù)對象的復(fù)雜業(yè)務(wù)實體。消息驅(qū)動Bean用于接收異步JMS消息。讓我們更詳細(xì)的認(rèn)識這些類型。
會話Bean
會話Bean一般代表著業(yè)務(wù)流程中象"處理訂單"這樣的動作。會話Bean基于是否維護過度狀態(tài)分為有狀態(tài)或者無狀態(tài)。無狀態(tài)會話Bean 沒有中間狀態(tài)。它們不保持追蹤一個方法調(diào)用另一個方法傳遞的信息。因此一個無狀態(tài)業(yè)務(wù)方法的每一次調(diào)用都獨立于它的前一個調(diào)用;例如,稅費計算或者轉(zhuǎn)移賬款。 當(dāng)計算稅費額的方法被調(diào)用時,稅費值被計算并返回給調(diào)用的方法,沒有必要存儲調(diào)用者為將來調(diào)用備用的內(nèi)部狀態(tài)。因為它們不維護狀態(tài),所以這些Bean是僅僅由容器管理。當(dāng)客戶端請求一個無狀態(tài)的Bean實例時,它可以接收來自由容器管理的無狀態(tài)會話Bean實例集中的一個實例。也因為無狀態(tài)會話Bean能夠被共享,所以容器可以維護更少數(shù)量的實例來為大量的客戶端服務(wù)。簡單地象該Bean增加元注釋@Stateless 來指定一個 Java Bean作為一個無狀態(tài)會話Bean被部署和管理。
一個有狀態(tài)的會話Bean維護一個跨越多個方法調(diào)用的會話狀態(tài);例如在線購物籃應(yīng)用。當(dāng)客戶開始在線購物時,客戶的詳細(xì)信息從數(shù)據(jù)庫獲得。相同的信息對于當(dāng)客戶從購物籃中增加或者移除商品等等操作時被調(diào)用的其他方法也是可訪問的 。但是因為該狀態(tài)不是在會話結(jié)束,系統(tǒng)崩潰或者網(wǎng)絡(luò)失敗時保留,所以有狀態(tài)會話Bean是暫時的。當(dāng)一個客戶端請求一個有狀態(tài)會話Bean實例時,客戶端將會得到一個會話實例,該Bean的狀態(tài)只為給客戶端維持。通過向方法增加元注釋@Remove來告訴容器當(dāng)某個方法調(diào)用結(jié)束一個有狀態(tài)會話Bean實例應(yīng)該被移除。會話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是管理持久化數(shù)據(jù)的一個對象,潛在使用一些相關(guān)的Java對象并且可以依靠主鍵被***識別。通過包括@Entity 元注釋來指定一個類是一個實體Bean。實體Bean表示來自數(shù)據(jù)庫的持久化數(shù)據(jù),例如客戶表中的一個紀(jì)錄,或者一個員工表中的一個員工記錄。實體Bean也可以被多個客戶端共享。例如一個員工實體能夠被多個計算一個員工每年工資總額或者更新員工地址的客戶端使用。實體Bean對象特定變量能夠保持持久化。實體Bean中所有沒有@Transient 元注釋的變量需要考慮持久化。EJB3.0的一個主要特色是創(chuàng)建包含使用元數(shù)據(jù)注釋的對象/關(guān)系映射實體Bean的能力。例如,指定實體Bean的empId變量映射到employee表中的EMPNO屬性,象下面實例中一樣用@Table(name="Employees") 注釋這個表的名字和用@Column(name="EMPNO")注釋empId變量。另外,EJB3.0中的一個特色是你可以很容易的在開發(fā)時測試實體Bean,可以用Oracle Application Server Entity Test Harness在容器外部運行一個實體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();
- }
- }
|
#p#
消息驅(qū)動Bean
驅(qū)動Bean (MDB) 提供了一個實現(xiàn)異步通信比直接使用Java消息服務(wù)(JMS)更容易地方法。創(chuàng)建MDB接收異步JMS消息。容器處理為JMS隊列和主題所要求加載處理的大部分工作。它向相關(guān)的MDB發(fā)送所有的消息。一個MDB允許J2EE應(yīng)用發(fā)送異步消息,該應(yīng)用能處理這些消息。實現(xiàn)javax.jms.MessageListener接口和使用@MessageDriven注釋該Bean來指定一個Bean是消息驅(qū)動Bean。
消息驅(qū)動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
客戶端是訪問Bean的應(yīng)用程序。雖然沒有必要保存在客戶層,但是能夠作為一個獨立的應(yīng)用,JSP,Servlet,或者另一個EJB。客戶端通過Bean的遠(yuǎn)程或者本地接口訪問EJB中的方法,主要取決于客戶端和Bean運行在同一個還是不同的JVM中。這些接口定義了Bean中的方法,而由Bean類實際實現(xiàn)這些方法。當(dāng)一個客戶端訪問該Bean類中的一個方法時,容器生成Bean的一個代理,被叫做遠(yuǎn)程對象或者本地對象。遠(yuǎn)程或者本地對象接收請求,委派它到相應(yīng)的Bean實例,返回結(jié)果給客戶端。調(diào)用一個Bean中的方法,客戶端使用定義在EJB不是描述文件的名字查找到Bean。在以下實例中,客戶端使用上下文對象找到命名為"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();
- }
- }
|
總結(jié)
EJB3.0開發(fā)企業(yè)JavaBean是相當(dāng)容易的。此規(guī)范使用元數(shù)據(jù)注釋定義Bean的類型和暴露給客戶端的方法。因此,無論你將創(chuàng)建一個執(zhí)行特定任務(wù)的會話Bean還是映射一個表到實體Bean來更新數(shù)據(jù),你都能象使用普通Java對象和接口一樣進(jìn)行處理,在業(yè)務(wù)方法中使用元注釋向客戶端暴露方法。既然你已經(jīng)理解了EJB的基礎(chǔ),可以到OTN中EJB 3.0 Resources Page發(fā)現(xiàn)更多信息。
【編輯推薦】
- JavaBean與EJB的不同
- 基于EJB技術(shù)的商務(wù)預(yù)訂系統(tǒng)的開發(fā)
- Enterprise JavaBeans EJB技術(shù)
- EJB分布式對象基礎(chǔ)篇
- 學(xué)習(xí)EJB編程的簡單過程