引言
現在很多的企業都在使用開源框架開發自己的企業級應用,如 Struts、Spring 和 Hibernate 等。起初由于受到資金和規模等的限制,大部分應用都部署在 Tomcat 或 Jboss 等開源應用服務器上。但隨著業務不斷發展,對應用部署的安全和性能要求也越來越高,企業希望將現有的開源應用從開源服務器遷移到商業應用服務器之上,比如:WebSphere Application Server ( 以下簡稱為 WAS),通過 WAS 增強應用整體性能,并實現更加可靠的管理。本文將通過實例向大家介紹如何將開源應用從 Tomcat 遷移到 WAS,并幫助大家解決一些可能遇到的普遍問題。
基于 Eclipse 開發的 Struts、Spring 和 Hibernate 開源應用和開發環境的特點
隨著 Java 技術的逐漸成熟與完善,作為建立企業級應用的標準平臺,J2EE 平臺得到了長足的發展。借助于 J2EE 規范中包含的多項技術:Enterprise JavaBean (EJB)、Java Servlets (Servlet)、Java Server Pages (JSP)、Java Message Service (JMS) 等,大量的應用系統被開發出來。但是,在傳統 J2EE 應用的開發過程中也出現了一些問題,比如在存儲和讀取過程中使用大量 SQL 和 JDBC 操作,會降低編程的效率以及系統的可維護性;過去傳統的 J2EE 應用多采用基于 EJB 的重量級框架 ( 比如:EJB 2.1),這樣做的問題在于使用 EJB 容器進行開發和調試需要耗費大量時間并且耦合度非常高,不利于擴展。
在摸索過程中,各種開源框架孕育而生。開源框架以其免費、開源和簡單等特點逐漸成為開發人員的最愛,現在仍然有很多的企業使用開源框架開發自己的應用程序。在開源框架中使用最多的就是 Struts、Spring 和 Hibernate 整合框架 ( 以下簡稱 SSH 框架)。
典型的 J2EE 三層結構,分為表現層、中間層(業務邏輯層)和數據服務層。三層體系將業務規則、數據訪問及合法性校驗等工作放在中間層處理。客戶端不直接與數據庫交互,而是通過組件與中間層建立連接,再由中間層與數據庫交互。下面就介紹以下 SSH 框架在 J2EE 三層結構中的作用:
- Struts 是一個在 JSP Model2 基礎上實現的 MVC 框架,主要分為模型 (Model) 、視圖 (Viewer) 和控制器 (Controller) 三部分,其主要的設計理念是通過控制器將表現邏輯和業務邏輯解耦,以提高系統的可維護性、可擴展性和可重用性。
- Spring 是一個解決了許多 J2EE 開發中常見問題并能夠替代 EJB 技術的強大的輕量級框架。這里所說的輕量級指的是 Spring 框架本身,而不是指 Spring 只能用于輕量級的應用開發。Spring 的輕盈體現在其框架本身的基礎結構以及對其他應用工具的支持和裝配能力。與傳統 EJB ( 比如 EJB 2.1) 相比,Spring 可使程序研發人員把各個技術層次之間的風險降低。當然,隨著 Java EE 5 及 Java EE 6 中新 EJB 規范的出現,如:EJB 3.0, EJB 3.1,EJB 的開發變得越來越簡單。用戶可以根據自己的需求和能力,選擇合適的框架。想了解更多關于 Java EE 5 和 Java EE 6 中的內容,請參考參考資源 [4] 和 [5]。
- Hibernate 是一個數據持久層框架,是一種實現對象和關系之間映射 (O/R Mapping) 的工具,它對 JDBC 進行了輕量級的對象封裝,使程序員可以使用對象編程思想來操作數據庫。它不僅提供了從 Java 類到數據表的映射,也提供了數據查詢和恢復機制。相對于使用 JDBC 和 SQL 來操作數據庫,使用 Hibernate 能大大的提高開發效率。
SSH 框架雖然非常強大,但也有一些缺點,比如 : 相比 Servlet+JDBC 開發方式,復雜度增加了不少 ; 而且開源框架開發和部署的靈活性,使得其使用方式不是很符合現有的 J2EE 規范,從而導致從 Tomcat 或其他開源服務器上遷移到 WAS 會出現很多問題和異常。并且,因為默認的 Eclipse 或 MyEclipse 工具缺少 WAS 的運行時插件,使得開發的開源應用程序無法直接從 IDE 里部署到 WAS。接下來,我們會分步介紹從 Tomcat 遷移到 WAS 可能出現的問題,雖然不能涵蓋遷移過程中的所有問題,但希望能夠拋磚引玉,盡量解決一些普遍存在的問題。
以下使用的實例是利用 Struts2+Spring2+Hibernate3 開發的模擬醫院管理應用。其中功能模塊包括前臺的顯示模塊、登錄模塊、后臺的文章和藥品管理模塊、用戶管理模塊等基本模塊;數據庫包括藥品、文章、學生、教師和看病等數據表。我們利用 Struts 實現 MVC 模型處理前臺的各種請求;利用 Hibernate 將數據持久化并簡化對數據的查詢;利用 Spring 進行依賴注入控制整個業務邏輯層。圖 1 為應用的部分包和配置文件結構
圖 1. 應用部分包結構和相關配置文件
配置好 MYSQL,將應用部署到 Tomcat 正常顯示頁面如下:
圖 2. 應用主頁
這里需要注意的是,由于開源框架的開發和目錄結構不規范,導致在 WAS 中部署 WAR 文件失敗。您可能會看到諸如“EAR 文件可能已損壞或不完整。確保對于 WebSphere Application Server,該應用程序處于兼容的 Java 2 Platform, Enterprise Edition (J2EE) 級別。”這樣的錯誤。
圖 3. WAS 中應用部署錯誤
遇到上述錯誤的原因,可能是因為 WAR 文件中包含 EXE 文件或者 WAR 文件結構不規范,去掉這些文件或調整文件結構即可解決該錯誤。
遷移之前的準備工作
遷移之前的準備工作非常關鍵。我們首先要確保應用可以在 Tomcat 成功運行,當然我們還需要確認以下幾個方面:
- Tomcat 啟動正常
- Struts、Spring 和 Hibernate 所需要的 lib 包都包含在應用的 WAR 或者 EAR 包中
- 應用在 Tomcat 上部署并且啟動成功
- 應用的 Struts 功能啟動成功,并能正常處理請求
- 應用的數據庫連接正常,Hibernate 映射成功并能正常實現數據持久化
- 應用的 Spring 功能成功,并能將所需要的資源注入到應用中
- 測試應用的其他功能確保應用整體運行正常
同時查看 Tomcat、Eclipse 的日志,確保應用沒有編譯異常或錯誤。當然我們利用 Eclipse 或者 MyEclipse 開發應用時可能會用到 WAS 的插件,我們在部署之前一定要確保系統中只有一個 WAS 實例在運行。如果其他 WAS 實例運行,可能會出現端口沖突等錯誤,這時 WAS 會提示一些錯誤:
清單 1. WAS 端口沖突錯誤
org.omg.CORBA.INTERNAL: CREATE_LISTENER_FAILED_4 vmcid: 0x49421000 minor code:
Caused by: org.omg.CORBA.INTERNAL: CREATE_LISTENER_FAILED_4 vmcid: 0x49421000 minor
code: 56 completed: No
at com.ibm.ws.orbimpl.transport.WSTransport.createListener(WSTransport.java:719)
at com.ibm.ws.orbimpl.transport.WSTransport.initTransports(WSTransport.java:591)
at com.ibm.rmi.iiop.TransportManager.initTransports(TransportManager.java:155)
at com.ibm.rmi.corba.ORB.set_parameters(ORB.java:1212)
at com.ibm.CORBA.iiop.ORB.set_parameters(ORB.java:1662)
at org.omg.CORBA.ORB.init(ORB.java:364)
at com.ibm.ws.orb.GlobalORBFactory.init(GlobalORBFactory.java:86)
at com.ibm.ejs.oa.EJSORBImpl.initializeORB(EJSORBImpl.java:179)
at com.ibm.ejs.oa.EJSServerORBImpl.<init>(EJSServerORBImpl.java:102)
at com.ibm.ejs.oa.EJSORB.init(EJSORB.java:55)
at com.ibm.ws.runtime.component.ORBImpl.start(ORBImpl.java:379)
... 26 more
|
WAS 在啟動的時候拋出以上異常,這主要是因為端口沖突,我們可以查看系統中是否有已經啟動的 WAS 或者別的程序正在占用此端口。也可以通過修改概要文件 config\cells\cellname\nodes\nodename 目錄下的 serverindex.xml 文件中的端口解決。
應用和環境都沒問題了,我們就可以著手遷移應用了。
部署中 Struts 框架可能遇到的問題所遇到的問題
Struts 框架最早是作為 Apache Jakarta 項目的組成部分問世運作,它繼承了 MVC 的各項特性,并根據 J2EE 的特點,做了相應的變化與擴展。Struts 框架很好的結合了 Jsp,Java Servlet,Java Bean,Taglib 等技術。
不論是 Struts1 還是 Struts2,很多部署問題都跟 lib 包沖突有關,所以在部署應用的時候要盡量查看一下應用 WAR 文件本身是否存在相互沖突的 jar 文件,WAR 文件和 WAS 所帶的包是否存在相互沖突。我們總結了一些 Struts 包沖突的問題供大家參考:
啟動應用的時候報 Unable to load bean typecom.opensymphony.xwork2.ObjectFactory classorg.apache.struts2.impl.StrutsObjectFactory 錯誤。這種錯誤多是由于 WAS 中存在相同 sturts2-core jar 文件與應用 WAR 或者 EAR 文件中 struts 包沖突。建議刪除 WAR 包中的 jar 文件,即可解決此問題。
還有一種情況是在 Tomcat 下項目運行沒有任何問題,但把 WAR 包安裝在 WAS 中只能訪問 HTML 頁面了,其余的 Struts2 的請求和 JSP 頁面都不能訪問,提示您無權查看此頁面,查看 WAS 日志文件中發現,啟動時有類似錯誤:
清單 2. WAS 包沖突錯誤
[11-8-18 15:17:41:079 CST] 00000010 webapp E com.ibm.ws.webcontainer.webapp.WebApp
initializeExtensionProcessors SRVE0280E:
擴展處理器無法在工廠
[com.ibm.ws.jsp.webcontainerext.ws.WASJSPExtensionFactory@2bec2bec]
中進行初始化:java.lang.ClassCastException:
com.sun.faces.application.WebappLifecycleListener
incompatible with java.util.EventListener
……
[10-8-18 15:17:41:562 CST] 00000010 config I Initializing
Sun's JavaServer Faces implementation (1.2_07-b03-FCS) for context '/cc'
[10-8-18 15:17:44:579 CST] 00000010 webapp W com.ibm.ws.webcontainer.webapp
.WebApp initializeTargetMappings SRVE0269W: 找不到用于處理 JSP 的擴展處理器。
|
解決方法有兩種:
- 在應用程序服務器 -> [ 選擇所使用的服務器 ] -> Web 容器設置 -> Web 容器 -> 定制屬性,增加名稱為"com.ibm.ws.webcontainer.invokefilterscompatibility"的定制屬性,值設為 true。
- 或者檢查 WAR 文件的 lib 庫中是否存 jsf-api.jar,jsf-impl.jar,jstl-1.2.jar 三個 jar 文件。這是因為在使用 MyEclipse 開發時,MyEclipse 會自動將這三個 jar 文件加入到 lib 庫中,但 jsf-impl.jar 包中的 com.sun.faces.application.WebappLifecycleListener 與 java.util.EventListener 不兼容導致應用無法訪問,打開 WAR 包的 lib 目錄,刪除這三個 lib 包即可解決問題。
部署中 Spring 框架可能遇到的問題所遇到的問題
Spring 框架支持輕量級的企業應用開發。作為開源項目,Spring 框架得到了廣泛的支持。目前大多數 SSH 架構的開源應用以 Tomcat 作為開發以及測試的 Web 容器。 WAS 也同樣支持基于 Spring 框架的項目開發和部署,除了支持 Spring 框架本身的資源管理以及支持事務的特性外,WAS 也可以依靠自身的容器管理、事務支持等帶來更加可靠的運行時環境。本文該部分將初步介紹基于 Spring 框架的開源應用從 Tomcat 上移植到 WAS 上需要注意的方面。
使用 Spring 開發的應用可以同時使用 Struts 和 Hibernate。整合了 Struts、Spring 和 Hibernate 進行開發的應用只要保證需要的 JAR 包全部打包在應用中,便可以正確的部署到 WAS 上。其中,WAS 不提供 Tomcat 缺省提供的一些開源 JAR 包,需要將這些包包含在應用中。此外,WAS 提供了很多 J2EE 相關特性,如果 Spring 要使用這些特性,則需要對 Spring 做相關配置。
數據訪問
Spring 整合 Hibernate 時,數據源配置信息應該定義在 applicationContext.xml 文件中。清單 3 給出了一個典型的配置數據源信息的示例。您可以將這段代碼不做任何修改,加入到 applicationContext.xml 文件中,并放到打包之后的應用中,WAS 會自動識別并利用 Spring 框架完成數據源的配置。
清單 3. applicationContext.xml 文件中的數據源配置
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"></property>
<property name="url" value="jdbc:db2://localhost:50000/MYTEST"></property>
<property name="username" value="db2admin"></property>
<property name="password" value="password"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
</props>
</property>
<property name="mappingResources">
<list><value>com/ibm/user/Person.hbm.xml</value></list>
</property>
</bean>
|
您也可以使用 WAS 中已經配置好的數據源,在 Spring 的配置文件 applicationContext.xml 文件中聲明數據源的代理 Bean,將 WAS 的數據源等資源通過該 Bean 委托給 Spring 框架進行調用。清單 4 給出了一個使用該方式進行配置的 applicationContext.xml 文件的片段。應用在運行時會使用該 Bean 找到相應的數據源完成與數據庫的交互。
清單 4. applicationContext.xml 文件中配置 WAS 數據源
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value> java:comp/env/jdbc/SSHTestDB</value></property>
</bean>
|
事務管理
Spring 框架同 WAS 一樣支持兩種事務管理的方式,分別為編程式和聲明式。大多數的用戶會選擇聲明式的事務管理方式,這種方式也是推薦使用的。
通常情況下 Spring 事務管理的一個核心是 PlatformTransactionManager 接口,使用聲明方式的事務管理的類均實現該接口,如對數據源進行事務管理的 DataSourceTransactionManager,對 Hibernate 進行事務管理的 HibernateTransactionManager 等。用戶可以選擇繼續使用這些事務管理方法,在 applicationContext.xml 文件中做相應的配置,如清單 5 所示,然后打包部署到 WAS 上完成應用的安裝和配置。
清單 5. Spring 框架的事務管理配置
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
|
其中 ref=”dataSource” 對應于清單 3 中的 Bean id=”dataSource”;ref=”sessionFactory”對應于清單 3 中的 bean id="sessionFactory"。
WAS 支持 JTA,而 Spring 也提供了 JtaTransactionManager。因此也可以將 Spring 中的事務管理交給 WAS 來做。Spring 2.5 之后提供的特定于 WAS 的事務管理的實現類為 WebSphereUowTransactionManager,您可以在 applicationContext.xml 文件中進行相應的配置,將事務的管理交由 WAS 來做。如清單 6 所示。其中配置的 bean id="transactionManager" 并不需要知道自己為哪些資源負責,因為它使用了 WAS 容器的全局事務管理體系。
清單 6. Spring 配置 WAS 的事務管理
<bean id="txManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager">
<ref local="txManager"/>
</property>
</bean>
|
部署中 Hibernate 框架可能遇到的問題所遇到的問題
Hibernate 做為數據持久層框架非常靈活,易于上手,并且便于與其它開源框架整合,從而使它成為開源解決方案中數據持久層框架的不二選擇。Hibernate 從 3.2 開始,就開始兼容 JPA。Hibernate3.2 獲得了 Sun TCK 的 JPA (Java Persistence API) 兼容認證。這使它的應用范圍更加廣泛。這里介紹將使用 Hibernate 做為持久層的應用移植到 WAS 上時需要注意的方面。
在項目初期,由于定位或需求的原因,很多 Hibernate 應用都使用 Tomcat 或 Jboss 做為應用服務器。隨著項目規模越來越大,對應用的可靠性和安全要求越來越高,就會考慮向商業應用服務器的遷移。總的來說,對一個可以正常運行在 Tomcat 或 Jboss 上的應用來說,移植到 WAS 上非常簡單,并不需要做太多改動,只需要將應用所依賴的 Hibernate 相關 jar 包都打包在應用中,再更具情況對配置文件做輕微調整即可,不用修改任何 Java 源代碼。
保持原有連接方式
很多 Hibernate 應用采用 JDBC 的鏈接方式,即在配置文件 hibernate.cfg.xml 中配置 connection.url 屬性,指定數據庫鏈接信息。例如:<property name="connection.url">jdbc:db2://db2url:port/dbname</property>
這種應用程序往往還要使用第三方提供的數據庫連接池,例如 C3P0 等。如果在移植到 WAS 之后仍然想保持現有連接形式和數據庫連接池不變,則不需要對配置文件做任何修改,只需要將第三方提供的數據庫連接池所依賴的 jar 包文件一同打包到 WAS 應用中即可。例如將 C3P0 數據庫連接池 jar 文件 c3p0-0.9.1.jar 打包到應用程序 lib 目錄下。
使用 WebSphere Application Server 數據源
WAS 數據源有著眾多企業級優勢,很多用戶移植后都希望能使用到 WAS 做為企業級應用服務器數據層的強大功能,對 Hibernate 的移植也不例外。其實將 Hibernate 應用的數據源移植到 WAS 非常簡單,只需要在 hibernate.cfg.xml 配置文件中加入數據源屬性 connection.datasource 和 JNDI 提供商信息即可,無需修改任何源代碼。這里需要注意,一旦配置好 WAS 的數據源,WAS 將接管與數據庫通信的工作,如果在您以前的應用中使用了第三方數據庫連接池,將會產生沖突。解決方法也很簡單,只要將 hibernate.cfg.xml 配置文件中的關于第三方數據庫連接池的信息注釋或刪除即可。
總結起來可分為三步:
- 將數據庫連接信息
<property name="connection.url">jdbc:db2://db2url:port/dbname</property>
替換為 WAS 數據源信息
<property name="connection.datasource">jdbc/hibernate</property>
- 加入 jndi.class 屬性
<property name="jndi.class">com.ibm.websphere.naming.WsnInitialContextFactory</property>
- 注釋或刪除原有數據庫連接池相關屬性
總結
現在的開源框架越來越龐大,同一框架不同版本的區別也很大。這篇文章雖不能覆蓋開源框架遷移到 WAS 的所有問題,但總結的都是一些比較普遍的問題,力求讓用戶快速地發現和解決部署和遷移過程中的問題。在遷移過程中,應用的代碼基本不需要修改,只要配置和部署得當,從 Tomcat 將開源應用遷移到 WAS 并不是一件難事。