引言
有關J2EE應用程序到WebSphere應用程序服務器的移植,盡管IBM提供了很多的資料和文章來說明如何將運行在WebLogic上的應用程序移植到WebSphere上,但是大家可能還是有所疑惑:是否從WebLogic移植到WebSphere和從Tomcat、Jboss、Resin移植到WebSphere會有所不同呢?實際上,一個J2EE應用程序無論運行在什麼平台上,我們都可以用相同的方法將其移植到WebSphere上,這也是J2EE規范給我們帶來的好處。然而,移植往往不會是一帆風順的,移植的難度不僅取決於J2EE應用程序對J2EE規范的遵循程度,更取決於它所用到的非J2EE成分的可移植性。對於標准的J2EE應用程序,我們可以通過固定的步驟完成移植任務,而對於其他的部分,我們只能通過耐心的調試和探索,以尋求最佳的解決方案。在這篇文章裡,我們將詳細說明移植的方法和常見的問題,在後續的文章裡會具體講述我們在各個平台移植過程中所遇到的特殊問題和解決方法。
本文假定您熟悉J2EE規范,並且使用WebSphere Studio Application Developer開發過部署在WebSphere應用程序服務器上的J2EE應用程序。在閱讀完本文後,建議大家先從試驗入手,完成參考文檔中的樣例程序,從而對移植任務有一個更加具體的理解。
移植方法
一、 學習WebSphere Studio Application Developer,參見參考文檔1。
二、 從應用程序中挑選出最具代表性的子系統
1、這個子系統應該全面涵蓋系統的技術難點,參見常見的問題
2、歸納總結系統所需的配置和所依賴的類庫
三、 分析此子系統的架構,澄清其中各個模塊之間的依賴關系
1、 包括業務模塊之間的依賴關系,以及Web模塊和EJB模塊等程序模塊之間的依賴關系等。
2、 如果應用程序中存在過多的交叉引用關系,可以考慮在一定程度上調整系統的架構和文件組織結構,盡量避免模塊之間的交叉調用。
3、 一定要避免運行在同一個JAVA虛擬機的多個模塊中包含相同Java 類或類庫的多個副本。
四、 將這個剝離出來並重新調整過的子系統打包,並在原有的J2EE 服務器上驗證其可用性
1、在原有J2EE服務器上能夠單獨運行此子系統
2、將系統的配置和所需的類庫,針對WebSphere重新規劃,為了能夠有效地完成這一步驟,我們必須先熟悉WebSphere的基本概念,包括WebSphere classloader的體系結構,參見參考文檔2。
3、測試通過的子系統打包成EAR文件,導入到WebSphere Studio Application Developer中,根據任務視圖所提供的錯誤提示,修復所有構建時的錯誤。WebSphere Studio Application Developer提供了一個非常出色的錯誤診斷機制,可以讓開發人員輕松的定位並修復應用程序中存在的錯誤,並且根據錯誤的提示,開發人員可以在J2EE規范中方便的找到相應的章節,查看詳細信息
五、了解WebSphere classloader的體系結構,重新規劃共享類庫
1、避免共享類庫在多個模塊中存在副本
2、盡量提供一個移植性好的J2EE應用程序打包方案,在部署到不同的J2EE服務器時不需要做任何的改動
3、建議的方案
對於在Web模塊中共享的JAR文件
將JAR文件移到WebProject/webApplication/web-inf/lib文件夾中,這樣JAR文件會在構建時被自動裝載並在運行時生效
對於在所有EJB模塊和Web模塊中共享的JAR文件
a)將JAR文件導入到EAR項目的根目錄當中;
b)在EJB項目和Web項目中通過修改Manifest文件來添加對JAR文件的依賴關系。
注意:不推薦通過J2EE應用服務器的CLASSPATH來添加JAR文件,這樣會降低應用程序的可移植性。要避免同時包含JAR文件的不同版本,如果原來系統裡包含多個版本,則只保留其中一個即可。
六、調試子系統
1、先利用WebSphere Studio Application Developer的通用測試客戶機(UTC)對服務器端的EJB進行調試
2、客戶端應用程序和服務器端應用程序對接,調試客戶端程序
七、將子系統導出為EAR文件,發布到WebSphere應用程序服務器中,進行測試
八、估算移植剩余子系統的工作量,分工完成
九、集成測試
常見的問題
一、 對J2EE標准的遵循
幾乎沒有一個J2EE應用程序,在不經過任何改動的情況下,可以運行在WebSphere 應用服務器上,其中一個原因就是大多數的應用程序沒有完全遵循J2EE規范,並且很多J2EE應用服務器都在某種程度上放寬了對於應用程序的限制。
1、 何時使用PortableRemoteObject進行對象造型
基於IIOP協議,我們需要使用PortableRemoteObject來轉換返回的stub對象,而基於WebLogic使用的t3協議,這個操作是可選的
如果stub對應的是遠程接口,此方法是必要的;如果stub對應的是本地接口,此方法是可選的
如果在不需要的情況下(例如訪問本地接口的EJB時)使用了此方法,系統可以正常運行,但不推薦使用;如果在必需的情況下(例如訪問遠程接口的EJB時)沒有使用此方法,那麼系統會拋出ClassCastException
2、 EJB引用
根據EJB2.0規范,使用本地的JNDI上下文(Java:comp/env)來查找EJB是必須的。但是很多J2EE服務器對此放寬了要求,在使用全局的JNDI上下文時,同樣可以正常運行。然而,WebSphere則嚴格遵循了這一約束。
在部署描述符中需要添加EJB引用
每個EJB home都需要綁定一個全局的JNDI名稱,綁定信息會存放在ibm-ejb-jar-bnd.xmi文件中
在WebSphere中,每個EJB引用(ejb-ref)必須綁定一個全局JNDI名稱;而在WebLogic中,全局JNDI名稱不總是必需的,當使用ejb-link時,全局JNDI名稱是可選的
如果使用的是EJB的遠程接口,按照規范,需要通過本地的JNDI名稱和EJB引用來訪問。如果使用了全局的JNDI名稱訪問,也可以在WebSphere中正常運行,但這個操作是違規的,而且可能會導致將來的不兼容問題
3、對於本地接口的EJB引用
在WebSphere中,如果沒有使用本地JNDI名稱查找本地EJB,將會出錯
不需要使用PortableRemoteObject進行類型轉換
必須使用本地JNDI名稱
必須使用EJB引用
4、構建時的錯誤
先修復部署描述符的錯誤信息。根據任務視圖的提示,可以輕松定位和修復錯誤(主要包括部署描述符的版本信息、JNDI名稱、各種引用等等)
然後根據任務視圖的提示定位和修復編譯錯誤(比如Java CLASS的丟失等等)
5、異常處理
本地Home接口的方法中不允許拋出RemoteException
Bean方法中不允許拋出RemoteException
MDB不允許拋出應用程序異常,因為應用程序和MDB之間不存在調用關系
二、 J2EE1.3的特性
1. CMP2.0 連接工廠的部署
在WebSphere中,如果我們建立一個名為jdbc/Sample的數據源為CMP提供數據庫連接,則CMP將使用名為eis/jdbc/Sample_CMP的CMP connection factory實現和數據庫的綁定。
2. MDB/JMS的部署
MDB/JMS的部署在不同的平台上會有所差別,但我們並不需要關心這種差別,只需要關心他們在WebSphere上的配置情況,詳細步驟請查閱參考文檔3的174和176頁。
3. 本地接口的使用
在WebSphere中使用本地接口的EJB,需要在部署描述符中配置本地引用,並在客戶端代碼中使用前綴為"Java:comp/env/"的本地JNDI上下文進行JNDI查詢。
4. J2EE 基於表單的認證
WebLogic使用weblogic.servlet.security.ServletAuthentication類實現基於表單的認證;
WebSphere使用J2EE規范中的 j_security_check Servlet進行基於表單的認證。
三、 客戶端的移植問題
客戶端的構成多種多樣,可以是Servlet,JSP,Java Application,Delphi 客戶端等等,而客戶端程序和服務器端程序通信的方式也是多種多樣,可以通過HTTP、RMI/IIOP、SOAP、Web Services等等。在移植過程中我們需要注意下面幾點:
1、 Java Application客戶端
如果Java Application客戶端使用HTTP請求訪問WebSphere應用程序服務器,則可以使用不同廠商提供的JDK
如果Java Application客戶端使用IIOP請求訪問WebSphere應用程序服務器,則只能使用WebSphere專用的JDK
2、 T3協議
T3協議在某種程度上給程序員帶來了一些便利,然而由於T3協議是私有協議,所以降低了應用程序的可移植性。而IIOP協議則為應用程序帶來了更好的移植性。在WebSphere中只能使用IIOP協議進行JNDI的訪問,因此需要將引用T3協議的地方改成IIOP的方式。
3、 始上下文工廠和供應商可以被存放在配置文件中,也可以使用Java的-D參數進行配置,下面的示例展示了如何在代碼中直接設置初始上下文工廠和供應商
WebLogic
Properties h = new PropertIEs();
h.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL,"t3://localhost:7001");
InitialContext ctx = new InitialContext(h);
WebSphere Properties h = new PropertIEs(); h.put(Context.INITIAL_CONTEXT_FACTORY," com.ibm.websphere.naming.WsnInitialContextFactory "); h.put(Context.PROVIDER_URL,"iiop://localhost:2809/"); InitialContext ctx = new InitialContext(h);
4、 事務出理(Java.user.Transaction)
WebLogic
(UserTransaction)getInitialContext().lookup("Javax.transaction.UserTransaction");
WebSphere
(UserTransaction)getInitialContext().lookup("jta/usertransaction")
5、客戶端程序所需要的EJB interfaces和stubs
推薦的方法
a) 將這些文件添加到客戶端的JAR文件當中,或者
b)將這些文件打包到新的JAR文件中,然後再將此JAR文件添加到CLASSPATH當中
動態下載interfaces和stubs
RMI協議提供了動態下載interfaces和stubs的功能,但存在很多限制,所以不推薦使用
四、 數據映射
1、使用第三方的數據綁定技術(如TopLink,Hibernate,Castor,Kodo等等)可以在一定程度上提高可移植性
2、CMP 和 CMR
當EJB的名稱與表的名稱一致並且EJB成員變量的名稱與表的列名一致時,在WebSphere Studio Application Developer中選擇自頂向下(top-down)的映射即可;
當EJB的名稱和表的名稱不一致或者EJB成員變量的名稱與表的列名不一致時,在WebSphere Studio Application Developer中選擇中間相遇(meet-in-middle)的映射
應用程序特定的問題
每一個應用程序都會有自己獨特的地方,在移植過程中或多或少會出現超出"常見問題"范圍的其他問題,相信通過耐心的調試均可逐一解決。在以後的文章裡會介紹我們在項目中遇到的特定的問題和解決辦法。