一個客戶端應用的構成?
JNDI 是如何工作的
使用 home 接口
使用會話 bean
EJB 客戶端
看起來很特殊的 EJB 客戶端應用實質上一點也不特殊
可以是 applet, 應用程序, servlet, 或其它 bean
沒有過高的 overhead
編程模式簡單
JNDI
使用 JNDI (Java Naming and Directory Interface) 來查找一個 EJB home 接口
JNDI 是將名稱與對象匹配的服務(類似電話黃頁)
一個 "naming service"
一個服務器將對象添加到目錄樹上:Known as "binding" a name to an object
任何一種對象可以被加到目錄樹中
JNDI Context
一個 Context 是一個將名稱與對象綁定好的對象
Context 可以是嵌套的 (構成一個目錄結構):頂級的 context 對象是一個 InitialContext
Context 可以被 "列出" 來查看其中的內容
Binding
Context 接口定義了下列方法
void bind(String name, Object obj)
Object lookup(String name)
一個容器當 Bean 啟動後自動將 Bean 的名稱綁定到它的 home 對象上
一個客戶端通過名稱就可查找到 home 接口
為何使用 JNDI?
服務器和客戶端需要知道:
如何定位名稱服務器
在名稱服務器上對象的正確名稱
客戶端不知道如何定位 EJB 服務器:客戶端必需知道如何找到名稱服務器
通過名稱服務器存取的對象可以來自多方面:多個服務器可以構成命名空間
獲得您的 Bean
一旦您獲得一個 home 接口,您可以使用 create() 方法來獲得一個 bean 的引用:一旦您獲得對該 bean 的引用,您可以開始調用它的方法
不需要任何掃尾工作;只需簡單地"停止引用" bean
try {
MyBean bean = findMyBeanHome().create();
bean.computeSomethingOrOther(42);
...
} catch (NamingException e) {
// Handle the naming exception
}
找到回 Home 的路
每個 EJB 都有一個 home 接口
客戶端可從一個 JNDI context 獲得 home 接口
使用一個 helper 類將它 "narrow" 成正確類型
public MyBeanHome findMyBeanHome()
throws NamingException {
Context context = getInitialContext();
Object object = context.lookup("MyBean");
context.close();
return (MyBeanHome)PortableRemoteObject
.narrow(object, MyBeanHome.class);
}
創建一個 InitialContext
INITIAL_CONTEXT_FACTORY
創建初始 context 的類
與各廠商的實現相關
PROVIDER_URL
名稱服務器的位置 (URL 格式)
"IIOP://localhost:6543/" == 本地機器,端口 6543
public Context getInitialContext()
throws NamingException {
Hashtable propertIEs = new Hashtable(2);
propertIEs.put(Context.PROVIDER_URL, "iiop://localhost:6543/");
propertIEs.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.eJS.ns.jndi.CNInitialContextFactory");
return new InitialContext(propertIEs);
}
注意這些 "魔術" 值
這些 "常量" 不應該寫死在您的方法中
應該從一個 propertIEs 文件中獲得,或為 servlet "init" 參數,...
public Context getInitialContext()
throws NamingException {
Hashtable propertIEs = new Hashtable(2);
propertIEs.put(Context.PROVIDER_URL, getNameServerURL());
propertIEs.put(Context.INITIAL_CONTEXT_FACTORY,
getInitialContextFactoryClassName());
return new InitialContext(propertIEs);
}
要及時關閉 Context
Context 不是線程安全的 (thread-safe):當您要共享它們時要當心
一旦您獲得了對象的引用,您不再需要 context; 可以關閉它
...
Context context = getInitialContext();
Information info = null;
try {
info = (Information)context.lookup("information");
} catch (NamingException e) {
throw e;
} finally {
context.close();
}
...
引用 Bean
您可以不確定地引用一個 home 或 bean 類
實際上,我們建議您保存 home 接口如果您還將使用它們時:JNDI 的查找是開銷很大的
但要注意,home/bean 的引用不是 serializable 的
...
MyBean bean = findMyBeanHome().create();
bean.computeSomethingOrOther(42);
...
Servlet 示例
public void doGet(...) throws ... {
PrintWriter out = response.getWriter();
out.println("");
try {
BankAccount account = getBankAccountHome().findById(42);
double balance = account.getBalance();
out.print("Balance is: ");
out.println(balance);
} catch (Exception e) {
out.println("A problem has occurred with the server.");
}
out.println("");
}
public synchronized BankAccountHome getBankAccountHome()
throws NamingException{
if (bankAccountHome == null)
bankAccountHome = findBankAccountHome();
return bankAccountHome;
}