個新的接口可以使你更有效地訪問EJB。學習如何運用它們,以及何時運用它們。
by Rudy Dahbura
當前的EJB 2.0規范有新的接口功能,這在原先的EJB 1.1中是沒有的。學習運用這些新的功能,它們可以使你更容易地、更有效地訪問EJB。
缺點是什么呢?你將犧牲位置的獨立性,但有時侯,這種代價是值得的。了解何時、如何運用新的功能對編寫設計良好的EJB應用程序是至關重要的。
EJB 1.1規范給EJB客戶端提供了一個remote interface和一個remote home interface與EJB實例交互,得到位置的透明度。以類似的形式,EJB 2.0規范現在給EJB客戶端提供了一個local interface和一個local home interface來與共享同一個JVM的EJB實例交互。
EJB remote interface(javax.ejb.EJBObject)和remote home interface(javax.ejb.EJBHome)在本質上是Java RMI接口。遠程客戶端運用接口和與Java RMI-IIOP兼容的參數與EJBs通訊。參數和方法的結果值在同一個容器中傳遞,或者跨網絡傳遞到遠程容器。
這種編程模式給EJB客戶端提供了一種訪問EJB組件的方法,就好像這些組件是本地的一樣。然后,容器就可以透明地處理網絡通訊和執行其它功能。這種方法很適合粗粒度的(coarse-grained)方法調用,其中客戶端和EJBs之間的客戶端通訊保持到最小限度。
相反,EJB local interface(javax.ejb.EJBLocalObject)和local home interface(javax.ejb.EJBLocalHome)不是Java RMI接口,它們是EJB 2.0的新功能。本地客戶端——如其它EJBs,運用相同JVM中傳遞的參數直接與EJBs通訊。這種技術消除了網絡潛在的問題、參數復制的問題以及需要與Java RMI-IIOP兼容的問題。也意味著,EJB客戶端可以運用一個更輕量級的編程模式來訪問服務。該方法很適合細粒度的(fine-grained)方法調用,因為作為EJB實例的位于同一個JVM中的EJB客戶端可以用本地接口來避免不必要的費用。
引進本地客戶端產生的另一個顯著的變化就是類型的轉換。所有的EJB實例在運用前必須轉換到它們恰當的接口類型,所以,有時侯,在運用遠程客戶端時,要保證Java RMI-IIOP的兼容性,你必須在轉換EJB實例前運用java.rmi.PortableRemoteObject.narrow()來縮?。╪arrow)它。
但本地客戶端可以直接把EJB實例轉換成local home interface類型,如下面的代碼片段:
InitialContext initCtx = new
InitialContext();
ExampleLocalHome exampleLocalHome =
(ExampleLocalHome)initCtx.lookup("java:comp/
env/ejb/Example"); |
從local home創建了EJB實例:
ExampleLocal exampleLocal =
exampleLocalHome.create(); |
也許EJB 2.0的最有趣、最容易被忽視的一個方面就是session和entity beans可以同時運用遠程和本地接口,這就給了你很大的靈活性。運用兩種接口給了潛在的bean客戶端最大程度的自由,不管它們是不是在一起的。
<session>和<entity>元素描述了session和entity bean的部署屬性。EJB 1.1和EJB 2.0規范定義了兩個元素,<home>和<remote>。(以前的規范需要兩個元素,但它們在2.0版中是可選的)。它們分別包含EJB remote home interface和remote interface的完全資格類名。
類似地,EJB 2.0規范定義了兩個附加的元素,<local-home>和<local>。正如你預料的,它們包含EJB local home interface和local interface的完全資格類名。下面的代碼顯示了如何運用這些新元素:
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>...</ejb-name>
<local-home>...</local-home>
<local>...</local>
<ejb-link>...</ejb-link>
...
</session>
</enterprise-beans>
<assembly-descriptor>
...
</assembly-descriptor>
</ejb-jar>
|
聰明地訪問本地客戶端的一個實例
本地EJB客戶端的概念在如列表1所示的例子中得到了很好地闡明,其中顯示了一個無狀態session bean,它的local interface和它的local home interface。注意,接口不擴展java.rmi.Remote。
無狀態session bean的XML部署描述如下面的代碼所示,它也重點強調了<local>和<local-home>元素的運用:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC
'-//Sun Microsystems, Inc.//DTD Enterprise
JavaBeans 2.0//EN'
'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>Example</ejb-name>
<local-
home>com.acmecorp.ejb.ExampleLocalHome</
local-home>
<local>com.acmecorp.ejb.ExampleLocal</local>
<ejb-
class>com.acmecorp.ejb.ExampleBean</
ejb-class>
<session-
type>Stateless</session-type>
<transaction-
type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<method-permission>
<unchecked/>
<method>
<ejb-name>Example</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
<container-transaction>
<method>
<ejb-name>Example</ejb-name>
<method-name>*</method-name>
</method>
<trans-
attribute>NotSupported</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
|
然后,一個本地的客戶端創建并訪問一個已經創建的enterprise bean的實例。下面的代碼也顯示了如何轉換一個bean的實例,而不用先縮小它:
<%@ page errorPage="/error.jsp"
import="javax.naming.*,
com.acmecorp.ejb.*"
%>
<%
InitialContext initCtx = new InitialContext();
ExampleLocalHome exampleLocalHome =
(ExampleLocalHome)initCtx.lookup("java:comp/env/
ejb/Example");
ExampleLocal exampleLocal =
exampleLocalHome.create();
%>
<html>
<head>
<title>Default</title>
<link rel="STYLESHEET" type="text/css"
href="styles/default.css">
</head>
<body>
<pre class="code"><%=
exampleLocal.getMessage() %></pre>
</body>
</html>
|
在這個例子中,本地客戶端是一個JSP頁面,因此是一個Web組件。(在有些情況中,當Web組件位于相同的JVM中時,它們訪問EJB 2.0本地組件接口。)
最后是Web組件的部署描述:
<web-app>
<!-- EJB Reference information -->
<ejb-local-ref>
<ejb-ref-name>ejb/Example<
/ejb-ref-name>
<ejb-ref-type>Session<
/ejb-ref-type>
<local-home>com.acmecorp.ejb.ExampleLocalHome<
/local-home>
<local>com.acmecorp.ejb.ExampleLocal<
/local>
<ejb-link>Example</ejb-link>
</ejb-local-ref>
</web-app>
|
注意用<ejb-local-ref>元素來聲明本地EJB引用。通過<ejb-link>元素得到一個明顯的與EJB的鏈接。它的值必須等于EJB XML描述符中的<ejb-name>元素。
未來會有更大的靈活性?
目前還是公開草案的EJB 2.1規范為訪問無狀態session beans定義了一個Web services客戶端。遠程客戶端將以一種位置獨立的方式與無狀態session beans通訊,這種通訊主要運用SOAP 1.1通過HTTP進行基于XML的調用。因為XML、SOAP和HTTP是獨立于語言的,所以客戶端不需要是Java對象,可以是運行在不同平臺上的其它類型的對象。
到那時,EJB 2.0的新功能就會更受Java開發人員的歡迎了,使他們能夠創建代碼,更有效地運用本地和遠程接口。通過運用這些功能,并對你的設計能力進行正確的評估,你就可以創建應用程序,使它們最大限度地運用EJBs。
關于作者:Rudy Dahbura是位住在洛杉磯的軟件顧問。他在洛杉磯的Sierra Systems Group工作,他運用分布式對象技術已經有五年了。他的聯系方式是
rdahbura@sierrasystems.com。