配置Bean
Enterprise JavaBean令人不太習慣的地方是你並不運行它,而是配置它。根據所使用的容器,用一個打包工具來創建一個JAR文件,裡面包含EJB類,XML配置描述文件和helper類。
不過要真正理解EJB,最好自己嘗試一下。
每個EJB廠家都支持自己的配置工具。雖然某些工具或許更好用,不過大部分都是使用一樣的模式。本文中將使用Sun的Java 2 Enterprise Edition SDK(J2EE SDK)將bean打包並配置它。J2EE SDK配置工具叫deploytool,在SDK的bin目錄中。
啟動deploytool後,在文件菜單中選擇New Application。在New Application對話框中,輸入你想創建的EAR(Enterprise Archive)文件的名字(EAR文件是一個J2EE應用的JAR文件)。圖6.1展示了Hello World session bean的對話框信息。
**************圖6.1****************
然後在文件菜單中選擇New Enterprise Bean。需要的話,可以修改JAR文件的顯示名字。
在New Enterprise Bean向導中,按右下角的Add按鈕(在內容區域附近)。將顯示一個如圖6.2所示的對話框,在對話框中選擇構成EJB的class文件,選擇HelloWorldSession.class, HelloWorldSessionHome.class和HelloWorldSessionImpl. class文件,點擊Add按鈕。
**************圖6.2****************
接著,要告訴deploytool Enterprise Bean class、Home interface和Remote interface使用的類。可以設置bean的顯示名字,該名字只在deploytool中使用,還必須告訴該工具設計的bean是session bean還是entity bean,如果是一個session bean,那它是無狀態的還是有狀態的。圖6.3顯示了Hello World bean的配置項目。
**************圖6.3****************
指定實現EJB各個功能的類
由於Hello World的例子只是一個簡單的session bean,它沒有任何其它的配置要求,因此你可以按Next,然後按Finish。現在已經做好了配置bean的准備工作。
在配置前,必須確定EJB服務器正在運行。還可能需要告訴deploytool使用哪一種服務器,這個設置可以通過Server菜單選項中選擇Add進行。在服務器運行後,從Tools菜單上選擇Deploy Application。將顯示一個類似圖6.4中的對話框。
**************圖6.4****************
在配置EAR文件或者JAR文件時,通常還會得到一些額外的類,這些類在服務器處理bean的訪問時需要用到。如BEA的WebLogic服務器,在創建JAR文件時,就會產生這些類。對於J2EE SDK來說,在配置JAR文件時就得到了這些類。許多EJB服務器還會產生一個客戶端的JAR文件,它包含有客戶端訪問EJB時需要用到的類。不過並不是所有的服務器都需要產生一個客戶端的JAR文件。例如WebLogic可以在運行時動態地載入重要的類,所以無需要一個特別的JAR文件。不過J2EE SDK需要一個客戶端的JAR文件,需要告訴deploytool產生一個客戶端的JAR文件。在這個例子中,客戶端JAR文件的文字是helloClient.jar。
最後,要告訴EJB使用什麼JNDI名字。在一些服務器中,可以設置在JAR文件中。J2EE SDK在配置時才會要求提供該名字,這樣就可以用不同的名字配置相同的bean到不同的服務器中。圖6.5顯示了允許設置bean名字的對話框。
**************圖6.5****************
創建客戶訪問Session Bean
在實現和配置session bean,有人認為寫一個客戶端程序也是非常麻煩的,事實並不是這樣,使用Enterprise JavaBean寫一個客戶程序是很簡單的。
使用EJB時,只需要得到EJB Home接口的一個引用。在得到Home接口的引用後,就可以通過其中的create方法來創建一個bean實例,然後調用bean的Remote接口的方法。
當然,首先做的第一件事情是得到JNDI naming context的一個引用,它是命名系統的一個接口,通過使用命名系統來找到EJB和其它對象。要得到naming context的一個引用,最簡單的方法是創建一個InitialContext對象,如下:
Context namingContext = new InitialContext();
根據使用的應用服務器,在運行客戶端時, 可能需要提供一個帶有額外信息的屬性對象或者定義一個系統屬性對象。需要額外信息的原因是JNDI API(Java Naming API)提供命名系統的一個接口,但是它自己沒有提供命名服務。如果運行的是WebLogic,使用的就是WebLogic naming服務。同樣,如果運行的是JRun,使用的就是JRun naming服務。JNDI使用context factory來創建Context對象,但需要告訴它的是使用哪個類作為context factory。
如果運行的是WebLogic,這個context factory就被稱為weblogic.jndi.WLInitialContextFactory;例如:
java -Dnaming.factory.initial=weblogic.jndi.WLInitialContextFactory
還可以通過屬性對象來指定context factory,如下:
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
Context context = new InitialContext(p);
屬性對象的好處是不需要在命令行做額外的指定。缺點是代碼僅可以在WebLogic服務器下工作。雖然可能只使用一個廠家的服務,但是在可能的情況下,將與特定廠家相關的信息從源代碼中分離出來是一個很好的主意。
現在已經擁有了naming context,這樣就可以使用lookup方法來找到需要的EJB。例如,如果使用“HelloWorld”的JNDI名字來配置HelloWorldSession bean,以下的代碼可以找到該bean的Home接口:
HelloWorldSessionHome home = (HelloWorldSessionHome)
PortableRemoteObject.narrow(
context.lookup("HelloWorld"),
HelloWorldSessionHome.class);
使用EJB的時候,不能通過標准的Java強制轉換操作符來轉換遠程的引用。必須使用PortableRemoteObject.narrow。EJB使用一個稱為RMI-IIOP的特殊形式RMI,需要這個特殊的語法來作轉換。
必須要記住的是無需找到EJB的Remote接口,只需要Home接口;然後就可以使用Home接口的create和find方法來得到Remote接口。
列表6.4顯示了一個完整的客戶端程序。
Listing 6.4 Source Code for TestHello.java
package usingj2ee.hello;
import java.util.*;
import javax.naming.*;
import javax.rmi.*;
public class TestHello
{
public static void main(String[] args)
{
try
{
/** Creates a JNDI naming context for location objects */
Context context = new InitialContext();
/** Asks the context to locate an object named "HelloWorld" and expects the
object to implement the HelloWorldSessionHome interface */
HelloWorldSessionHome home = (HelloWorldSessionHome)
PortableRemoteObject.narrow(
context.lookup("HelloWorld"),
HelloWorldSessionHome.class
);
/** Asks the Home interface to create a new session bean */
HelloWorldSession session = (HelloWorldSession) home.create();
System.out.println("The default greeting is: "+
session.getGreeting());
session.setGreeting("Howdy!");
System.out.println("The greeting is now: "+session.getGreeting());
/** Destroy this session */
session.remove();
/** Now create a session with a different greeting */
session = (HelloWorldSession) home.create("Guten Tag!");
System.out.println("Created a new session with a greeting of: "+
session.getGreeting());
/** Destroy this session */
session.remove();
}
catch (Exception exc)
{
exc.printStackTrace();
}
}
}
圖6.6顯示了TestHello 程序的輸出。
**************圖6.6****************
TestHello類測試了HelloWorldSession bean的功能