海水正藍

          面朝大海,春暖花開
          posts - 145, comments - 29, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          如何在 WebSphere 中解決 jar 包沖突

          郝 愛麗, 高級軟件工程師, IBM 中國軟件開發(fā)中心
          常紅平, 軟件工程師, IBM中國軟件開發(fā)中心

          簡介: 

          Jar 包沖突問題是在大型 Java 軟件開發(fā)中經(jīng)常遇到的問題,系統(tǒng)開發(fā)人員經(jīng)常會為解決類似的問題耗費大量的時間進行調(diào)試和測試,本文根據(jù)各種際情況,結(jié)合 WebSphere 中類加載器,討論了幾種解決 jar 包沖突問題的辦法,并給出了具體實現(xiàn)的步驟及源代碼。

          讀者定位為具有 Java 和 WebSphere 開發(fā)經(jīng)驗的開發(fā)人員。

          讀者可以學(xué)習(xí)到在 WebSphere 中類加載器的定義以及解決 jar 包沖突問題的幾種辦法,并可以直接使用文章中提供的 Java 代碼,從而節(jié)省他們的開發(fā)和調(diào)試時間,提高效率。



          大型的基于 WebSphere 的項目開發(fā)中,同一個 WebSphere Application Server(以下簡稱 WAS)上會部署多個應(yīng)用程序,而這多個應(yīng)用程序必然會共用一些 jar 包,包括第三方提供的工具和項目內(nèi)部的公共 jar 等。把這些共用的 jar 包提取出來在多個應(yīng)用程序之間共享,不僅可以統(tǒng)一對這些 jar 包進行維護,同時也提高了 WAS 的性能。但是隨著應(yīng)用的不斷擴大,新的應(yīng)用程序的不斷增加,新的應(yīng)用程序會希望使用一些更高版本的共享 jar 包,而由于系統(tǒng)運行維護的需要,老的應(yīng)用程序仍然希望用老版本的共享 jar 包,這樣就必然造成了共享 jar 包的版本沖突。jar 包版本沖突問題是在大型應(yīng)用項目的開發(fā)中經(jīng)常遇到的問題,本文試圖從 WebSphere 的類加載器入手,討論幾種在不同情況下解決 jar 包沖突問題的辦法。

          WebSphere 中類加載器介紹

          Jar 包沖突實際上是應(yīng)用程序運行時不能找到真正所需要的類,而影響類的查找和加載的是 JVM 以及 WebSphere 中的類加載器(class loader),為此,我們首先介紹一下 WebSphere 中的類加載器以及一些相關(guān)的概念。

          WebSphere 中類加載器層次結(jié)構(gòu)

          Java 應(yīng)用程序運行時,在 class 執(zhí)行和被訪問之前,它必須通過類加載器加載使之有效,類加載器是 JVM 代碼的一部分,負責(zé)在 JVM 虛擬機中查找和加載所有的 Java 類和本地的 lib 庫。類加載器的不同配置影響到應(yīng)用程序部署到應(yīng)用程序服務(wù)器上運行時的行為。JVM 和 WebSphere 應(yīng)用程序服務(wù)器提供了多種不同的類加載器配置, 形成一個具有父子關(guān)系的分層結(jié)構(gòu)。WebSphere 中類加載器的層次結(jié)構(gòu)圖 1 所示:


          圖 1:WebSphere 中類加載器的層次結(jié)構(gòu)
          圖 1:WebSphere 中類加載器的層次結(jié)構(gòu)

          如上圖所示,WebSphere 中類加載器被組織成一個自上而下的層次結(jié)構(gòu),最上層是系統(tǒng)的運行環(huán)境 JVM,最下層是具體的應(yīng)用程序,上下層之間形成父子關(guān)系。

          • JVM Class loader:位于整個層次結(jié)構(gòu)的最上層,它是整個類加載器層次結(jié)構(gòu)的根,因此它沒有父類加載器。這個類加載器負責(zé)加載 JVM 類, JVM 擴展類,以及定義在 classpath 環(huán)境變量上的所有的 Java 類。
          • WebSphere Extensions Class loader:WebSphere 擴展類加載器 , 它將加載 WebSphere 的一些 runtime 類,資源適配器類等。
          • WebSphere lib/app Class loader:WebSphere 服務(wù)器類加載器,它將加載 WebSphere 安裝目錄下 $(WAS_HOME)/lib/app 路徑上的類。 在 WAS v4 版本中,WAS 使用這個路徑在所有的應(yīng)用程序之間共享 jar 包。從 WAS v5 開始, 共享庫功能提供了一種更好的方式,因此,這個類加載器主要用于一些原有的系統(tǒng)的兼容。
          • WebSphere "server" Class loader:WebSphere 應(yīng)用服務(wù)器類加載器。 它定義在這個服務(wù)器上的所有的應(yīng)用程序之間共享的類。WAS v5 中有了共享庫的概念之后,可以為應(yīng)用服務(wù)器定義多個與共享庫相關(guān)聯(lián)的類加載器,他們按照定義的先后順序形成父子關(guān)系。
          • Application Module Class Loader:應(yīng)用程序類加載器,位于層次結(jié)構(gòu)的最后一層,用于加載 J2EE 應(yīng)用程序。根據(jù)應(yīng)用程序的類加載策略的不同,還可以為 Web 模塊定義自己的類加載器。

          關(guān)于 WebSphere 的類加載器的層次結(jié)構(gòu),以下的幾點說明可能更有助于進一步的理解類的查找和加載過程:

          • 每個類加載器負責(zé)在自身定義的類路徑上進行查找和加載類。
          • 一個子類加載器能夠委托它的父類加載器查找和加載類,一個加載類的請求會從子類加載器發(fā)送到父類加載器,但是從來不會從父類加載器發(fā)送到子類加載器。
          • 一旦一個類被成功加載,JVM 會緩存這個類直至其生命周期結(jié)束,并把它和相應(yīng)的類加載器關(guān)聯(lián)在一起,這意味著不同的類加載器可以加載相同名字的類。
          • 如果一個加載的類依賴于另一個或一些類,那么這些被依賴的類必須存在于這個類的類加載器查找路徑上,或者父類加載器查找路徑上。
          • 如果一個類加載器以及它所有的父類加載器都無法找到所需的類,系統(tǒng)就會拋出 ClassNotFoundExecption 異常或者 NoClassDefFoundError 的錯誤。

          類加載器的委托模式

          類加載器有一個重要的屬性:委托模式(Delegation Mode,有時也稱為加載方式:Classloader mode)。委托模式?jīng)Q定了類加載器在查找一個類的時候, 是先查找類加載器自身指定的類路徑還是先查找父類加載器上的類路徑。

          類加載器的委托模式有兩個取值:

          • Parent_First:在加載類的時候,在從類加載器自身的類路徑上查找加載類之前,首先嘗試在父類加載器的類路徑上查找和加載類。
          • Parent_Last:在加載類的時候,首先嘗試從自己的類路徑上查找加載類,在找不到的情況下,再嘗試父類加載器類路徑。

          有了委托模式的概念,我們可以更加靈活的配置在類加載器的層次結(jié)構(gòu)中類的加載和查找方式。表 1 中給出了在 WebSphere 的類加載器層次結(jié)構(gòu)中各個類加載器的委托模式的定義,并給出了不同的類加載器內(nèi)類的生命周期。


          表 1:WebSphere 中類加載器的委托模式及相應(yīng)類的生命周期

          注意:在上表中,"JVM Class loader" 因為在類加載器的最頂層,它沒有父類加載器,因此其委托模式為 N/A,"WebSphere Extensions Class loader"和"WebSphere lib/app Class loader"的委托模式固定為表中的取值,不可配置,其它的類加載器的委托模式都是可以配置的。

          WebSphere 中的類加載器策略

          WebSphere 中對類加載器有一些相關(guān)的配置,稱為類加載器策略(class loader policy)。類加載器策略指類加載器的獨立策略(class loader isolation policy), 通過類加載器策略設(shè)置,我們可以為 WAS 和應(yīng)用程序的類加載器進行獨立定義。

          每個 WAS 可以配置自己的應(yīng)用程序類加載器策略,WAS 中的每個應(yīng)用程序也可以配置自己的 Web 模塊類加載器策略,下面我們對這兩種策略分別介紹。

          1 .應(yīng)用服務(wù)器(WAS)配置:應(yīng)用程序類加載器策略

          應(yīng)用服務(wù)器對應(yīng)用程序類加載器策略有兩種配置:

          • Single:整個應(yīng)用服務(wù)器上的所有應(yīng)用程序使用同一個類加載器。在這種配置下,每個應(yīng)用程序不再有自己的類加載器。
          • Multiple:應(yīng)用服務(wù)器上的每個應(yīng)用程序使用自己的類加載器。

          2 .應(yīng)用程序配置:Web 模塊類加載器策略

          應(yīng)用程序中對 Web 模塊類加載器有兩種配置:

          • Application:整個應(yīng)用程序內(nèi)的所有的實用程序 jar 包和 Web 模塊使用同一個類加載器。
          • Module:應(yīng)用程序內(nèi)的每個 Web 模塊使用自己的類加載器。應(yīng)用程序的類加載器仍然存在,負責(zé)加載應(yīng)用程序中 Web 模塊以外的其它類,包括所有的實用程序 jar 包。

          從上面的定義可以看出,不同的類加載器策略的配置下,類加載器的層次結(jié)構(gòu)上的某些類加載器可能不存在。比如在應(yīng)用程序服務(wù)器的應(yīng)用程序類加載 器策略定義為 single 的情況下,應(yīng)用程序的類加載器將不存在,同一個應(yīng)用服務(wù)器上的所有應(yīng)用程序?qū)⒐灿猛粋€類加載器,這也就意味著不同的應(yīng)用程序之間的類是共享的,應(yīng)用程序 間不能存在同名的類。

          回頁首

          在 WebSphere 中解決 jar 包沖突

          Jar 包沖突問題實際上就是應(yīng)用程序希望用某一個確定版本的 jar 包中的類,但是類加載器卻找到并加載了另外一個版本的 jar 包中的類。在上一部分介紹了 WebSphere 中類加載器的基本概念和相關(guān)配置之后,我們來看如何在 WebSphere 中解決 jar 包沖突。

          在 WAS v5 版本之前,使用共享 jar 包的方式是將 jar 包放在 $(WAS_HOME)/lib/app 路徑下,從上一部分中,我們可以看到,這個路徑正是"WebSphere lib/app Class loader" 類加載器的類查找路徑,WebSphere 會查找這個路徑以取得相應(yīng)得 jar 包中的 Java 類,從而做到在 WebSphere ND 上的多個應(yīng)用程序之間共享 jar 包的目的。但是這樣做的一個缺點就是這些共享 jar 包暴露給 WebSphere ND 上所有的應(yīng)用程序,對于那些希望使用 jar 包其它版本的應(yīng)用程序,這些 jar 包也同樣存在在了它們的類加載器類路徑上,因此,就不可避免的會造成版本的沖突。在 WAS v5 版本及之后,增加了共享庫(shared library)的概念,推薦的在多個應(yīng)用程序間共享 jar 包并避免 jar 包沖突的方式是使用共享庫。

          具體分析引起 jar 包沖突的情況,主要有三種:

          • 多個應(yīng)用程序間 jar 包沖突:多個應(yīng)用程序間由于使用了共享 jar 包的不同版本而造成 jar 包版本沖突。
          • 應(yīng)用程序中多個 Web 模塊間 jar 包沖突:同一個應(yīng)用程序內(nèi)部,不同的 Web 模塊間同時使用一個 jar 包的不同版本而造成 jar 包版本沖突。
          • 應(yīng)用程序中同一個 Web 模塊內(nèi) jar 包沖突:同一個應(yīng)用程序內(nèi)部,同一個 Web 模塊內(nèi),由于需要同時使用同一個 jar 包的兩個版本而造成的 jar 包沖突

          本部分根據(jù)這三種 jar 包沖突的情況,討論三種解決 jar 包沖突的辦法,并具體討論三種解決辦法的實現(xiàn)步驟和適用情況:

          • 共享庫方式解決 jar 包沖突:主要解決應(yīng)用程序間的 jar 包沖突問題
          • 打包到 Web 模塊中解決 jar 包沖突:主要解決應(yīng)用程序中多個 Web 模塊間 jar 包沖突問題
          • 命令行運行方式解決 jar 包沖突:主要解決應(yīng)用程序中同一個 Web 模塊內(nèi) jar 包沖突問題

          共享庫方式解決 jar 包沖突

          在 WAS v5 中,提供了一種很好的機制,使得 jar 包只存在于需要這個 jar 包的應(yīng)用程序的類加載器的路徑上,而其它的應(yīng)用程序不受它的任何影響,這就是共享庫(Shared library)。共享庫可以用在應(yīng)用服務(wù)器級別和應(yīng)用程序級別,使用應(yīng)用程序級別的共享庫,其好處就是在不同的應(yīng)用程序之間使用共享 jar 包的不同版本。我們可以為一些通用 jar 包的每個不同版本定義成不同的共享庫,應(yīng)用程序希望使用哪個版本,就把這個版本的共享庫放到應(yīng)用程序的類加載器的類路徑上,這種方式有效的解決了應(yīng)用程序 之間 jar 包沖突的問題。

          下面舉例介紹定義和使用共享庫的具體方法,本例中,假設(shè)存在 xerces.jar 包版本沖突。

          1 . 定義共享庫

          系統(tǒng)管理員可以在 WebSphere 的 Admin console 中定義共享庫,可以分別在 Cell、Node 以及 server 的級別上定義。

          • 步驟一 : 進入 Admin console,選擇 Environment > Shared Library > new。如圖 2 所示:

            圖 2:WebSphere Admin Console 中進入共享庫頁面
            圖 2:WebSphere Admin Console 中進入共享庫頁面
          • 步驟二: 給出共享庫的名字,并指定共享的文件和目錄。多個不同的文件 / 目錄之間通過"Enter"鍵分隔,且不能有路徑分隔符,如":"和";"等。如圖 3 所示:

            圖 3:WebSphere Admin Console 中添加共享庫
            圖 3:WebSphere Admin Console 中添加共享庫
          • 步驟三:點擊 Apply 或者 OK 之后,就添加了一個名字為 Xerces V2.0 的共享庫。記住添加完成后一定要在 admin console 保存配置。如圖 4 所示:

            圖 4:WebSphere Admin Console 中共享庫列表
            圖 4:WebSphere Admin Console 中共享庫列表

          2 .安裝應(yīng)用程序

          進入 Admin console,選擇 Applications > Install New Application 安裝應(yīng)用程序。請參照 IBM WebSphere 的 Admin console 使用手冊進行安裝新的應(yīng)用程序,此處不再詳細介紹。

          3 .將共享庫關(guān)聯(lián)到應(yīng)用程序

          • 步驟一:進入 Admin console,選擇 Applications > Enterprise applications ,并選擇需要使用共享庫的應(yīng)用程序。注意:因為要改變應(yīng)用程序的設(shè)置,所以如果應(yīng)用程序已經(jīng)運行,需要先停掉應(yīng)用程序。如圖 5 所示:

            圖 5:WebSphere Admin Console 中選擇需要配置的應(yīng)用程序
            圖 5:WebSphere Admin Console 中選擇需要配置的應(yīng)用程序
          • 步驟二 : 點擊應(yīng)用程序,進入后,選擇 Libraries。如圖 6 所示:

            圖 6:WebSphere Admin Console 中選擇應(yīng)用程序庫屬性
            圖 6:WebSphere Admin Console 中選擇應(yīng)用程序庫屬性
          • 步驟三 : 點擊 Add,為應(yīng)用程序添加共享庫。如圖 7 所示:

            圖 7:WebSphere Admin Console 中應(yīng)用程序添加庫
            圖 7:WebSphere Admin Console 中應(yīng)用程序添加庫
          • 步驟四 : 從下拉列表中選擇所需要的共享庫,點擊 OK。如圖 8 所示:

            圖 8:WebSphere Admin Console 中應(yīng)用程序添加庫頁面指定所用的共享庫
            圖 8:WebSphere Admin Console 中應(yīng)用程序添加庫頁面指定所用的共享庫

          這樣,Xerces V2.0 共享庫定義的 xerces 版本就存在于了應(yīng)用程序類加載器的類加載路徑上。注意,在添加完成后要保存服務(wù)器的設(shè)置。

          4 .設(shè)置應(yīng)用程序的類加載器的委托模式為 Parent_Last

          為了進一步防止共享庫定義的 jar 包的其它版本已經(jīng)存在于 JVM 或者 WebSphere 的類加載器路徑上,還需要設(shè)置應(yīng)用程序的類加載器的委托方式為 Parent_Last。

          • 步驟一:進入 Admin console,選擇 Applications > Enterprise applications > ,選擇需要配置的應(yīng)用程序。如圖 9 所示:

            圖 9:WebSphere Admin Console 中選擇需要配置的應(yīng)用程序
            圖 9:WebSphere Admin Console 中選擇需要配置的應(yīng)用程序
          • 步驟二:點擊進入應(yīng)用程序,設(shè)置類加載器的委托模式為 Parent_Last。注意:在配置完成后,要保存配置,最后啟動應(yīng)用程序。如圖 10 所示:

            圖 10:WebSphere Admin Console 中為應(yīng)用程序設(shè)置類加載器委托模式
            圖 10:WebSphere Admin Console 中為應(yīng)用程序設(shè)置類加載器委托模式

          通過上面的配置,即使 xerces 的其它版本已經(jīng)存在于系統(tǒng)中,應(yīng)用程序在運行時,其類加載器也會首先查找并加載指定的共享庫中的 xerces 版本。這樣我們就通過使用共享庫的方式,解決了 jar 包版本沖突問題。

          打包到 Web 模塊中解決 jar 包沖突

          共享庫的方式,只是在應(yīng)用程序的層次上,在多個應(yīng)用程序之間解決了共享 jar 包造成的版本沖突問題,如果一個應(yīng)用程序的內(nèi)部,其中一個 Web 模塊使用了一個 jar 包的 A 版本,而另一個 Web 模塊使用這個 jar 包的 B 版本,在這種情況下造成的 jar 包沖突,共享庫的方式是無法解決的,我們可以考慮將其中一個在多個應(yīng)用程序間共享的 jar 包版本,比如 A 版本,定義成共享庫,或者放在"WebSphere lib/app Class loader"類加載器路徑上供多個應(yīng)用程序使用,而將 B 版本的 jar 包打包到使用它的 Web 模塊中的方式來解決沖突。

          其次,目前很多在線的系統(tǒng)是 WAS v4 的遺留系統(tǒng),其上運行的應(yīng)用程序已經(jīng)使用了"WebSphere lib/app Class loader"類加載器,將 jar 包放在 $(WAS_HOME)/lib/app 目錄下進行共享。如果由于其中某個應(yīng)用程序的升級或者新增加某個應(yīng)用程序,需要使用某個共享 jar 包的其它版本,在這種情況下,為了減少對系統(tǒng)的影響,也可以考慮將這個共享 jar 包的新版本打包到升級(或新增)的應(yīng)用程序中的方式來解決 jar 包沖突。

          由于 Web 模塊的 WebContent/WEB-INFO/lib 目錄在應(yīng)用程序 Web 模塊的類加載器查找路徑上,因此,我們可以把 jar 包放在這個目錄下,Web 模塊的類加載器將自動查找并加載這個 jar 包中的類。

          • 步驟一:在 WSAD IE 集成開發(fā)環(huán)境中,將沖突 jar 包放在 Web 模塊的 WebContent/WEB-INFO/lib 目錄下。如圖 11 所示:

            圖 11:WSAD IE 中為 Web 模塊添加庫
            圖 11:WSAD IE 中為 Web 模塊添加庫
          • 步驟二:在 Admin console 中,將應(yīng)用程序部署到 WebSphere server 上之后,進入 Applications > Enterprise Applications, 選擇相應(yīng)的應(yīng)用程序,并確認應(yīng)用程序不在運行狀態(tài) ( 參見前面章節(jié)中選擇應(yīng)用程序的步驟 )。點擊進入應(yīng)用程序,確認應(yīng)用程序的類加載器的委托模式為 Parent_First, 應(yīng)用程序的類加載器策略為 Module。如圖 12 所示:

            圖 12:WebSphere Admin Console 中應(yīng)用程序?qū)傩耘渲庙撁? src=
            圖 12:WebSphere Admin Console 中應(yīng)用程序?qū)傩耘渲庙撁?/li>
          • 步驟三:在同一個頁面上,選擇 Web Modules,點擊進入。如圖 13 所示:

            圖 13:WebSphere Admin Console 中選擇應(yīng)用程序 Web 模塊屬性
            圖 13:WebSphere Admin Console 中選擇應(yīng)用程序 Web 模塊屬性
          • 步驟四:點擊相應(yīng)的包含沖突 jar 包的 Web 模塊,設(shè)置 Web 模塊的類加載器的委托模式為 Parent_Last。注意:在設(shè)置完成后要保存服務(wù)器配置,并啟動應(yīng)用程序。如圖 14 所示:

            圖 14:WebSphere Admin Console 中為 Web 模塊指定類加載器委托模式 圖 14:WebSphere Admin Console 中為 Web 模塊指定類加載器委托模式

          將沖突 jar 包打包到 Web 模塊中,并設(shè)置相應(yīng) Web 模塊的類加載器的委托模式為 Parent_Last,應(yīng)用程序在運行過程中加載類的時候,這個 Web 模塊的類加載器會首先查找 WebContent/WEB-INFO/lib 目錄下的 jar 包進行類的加載;而對于其它的 Web 模塊,由于其類加載器的委托模式仍然為缺省的 Parent_First,它們的類加載器仍然首先從應(yīng)用程序的共享庫或者 WebSphere 的共享路徑上加載 jar 包中的類,從而解決了 jar 包沖突的問題。

          命令行運行方式解決 jar 包沖突

          不論是設(shè)置共享庫,還是將沖突 jar 包打包到應(yīng)用程序中,其解決的問題都是在應(yīng)用程序的一個 Web 模塊中只使用了沖突 jar 包的一個版本的情況。我們在開發(fā)中曾經(jīng)遇到過這樣的情況:應(yīng)用程序的 Web 模塊中已經(jīng)使用了 1.4 版本的 xerces.jar,由于 Web 功能的擴展,在這個模塊中又引入一個新的第三方工具,而這個第三方工具需要使用 2.0 版本的 xerces.jar 才能正常工作,這種情況下的 jar 包沖突如何解決呢?

          在前面類加載器的部分已經(jīng)介紹過,每個應(yīng)用程序的一個 Web 模塊最多只能有一個類加載器,而 Web 模塊的類加載器中加載的類的生命周期為整個應(yīng)用程序的運行期,也就是說,Web 模塊加載器不可能同時加載一個類的兩個版本,同時,Web 模塊的類加載器的委托模式也是在應(yīng)用程序運行前設(shè)置的,在應(yīng)用程序運行期內(nèi)無法改變的,因此,上面描述的在一個 Web 模塊中同時使用兩個版本的 jar 包的問題,象前兩種方法那樣配置運行在一個 JVM 內(nèi)的類加載器的設(shè)置的方法是無法解決的。

          唯一的解決辦法就是在應(yīng)用程序運行的 JVM 外,啟動另外一個 JVM 來運行調(diào)用沖突 jar 包的代碼,因為兩個不同的 JVM 可以加載各自的類,從而解決 jar 包沖突問題。

          這種情況下,原來使用 jar 包的老版本的方式(包括 jar 包放置路徑,共享庫設(shè)置方式,類加載器的委托模式等)不變,將對 jar 包新版本的調(diào)用通過命令行運行方式實現(xiàn)。具體做法是:將對 jar 包新版本內(nèi)功能的調(diào)用,封裝到一個可以單獨運行的類中,在 Web 模塊中以命令行方式運行這個類。同時把這個類以及 jar 包的新版本放在任意一個 was 可訪問的路徑上(比如 /usr/WebSphere),在命令行的 classpath 參數(shù)中包含這個路徑(比如 /usr/WebSphere)。

          下面通過舉例說明命令行運行方式的編程過程,在本例中,假設(shè) TestEar 應(yīng)用程序的 Web 模塊 TestWar 中,已經(jīng)使用了 conflict_v1.jar,由于新添功能需要使用 conflict_v2.jar 中的 exampleCall() 功能。

          沖突 jar 包 conflict_v2.jar 提供的功能:


          代碼 1:沖突 jar 包 conflict_v2.jar 功能
           1  Package com.ibm.conflict; 
           2 
           3  Public class ConflictClass{ 
           4     …… . 
           5  Public static String exampleCall(string param){ 
           6     String rs; 
           7     …… ; 
           8     Return rs; 
           9  } 
          10 ……

          不存在沖突問題時的編碼舉例:

          如果沒有 jar 包沖突問題,則對這個功能的調(diào)用是簡單的,只需要將 conflict_v2.jar 放在應(yīng)用程序自身或者其父類加載器的查找路徑上,然后在 Web 模塊中直接調(diào)用即可,如下:


          代碼 2:不存在沖突時的調(diào)用方式
          1 Public String methodA(String param){ 
          2    ……
          3    String rs = ConflictClass.exampleCall(param); 
          4    ……
          5    Return rs; 
          6  }

          存在沖突后的命令行運行方式編碼舉例

          針對 jar 包沖突問題,我們需要在 Web 模塊中做如下的修改:

          • 步驟一:將沖突 jar 包放在 was 可訪問的路徑上,比如 /usr/WebSphere/conflict_v2.jar。
          • 步驟二:將對包含沖突代碼的調(diào)用封裝到一組可單獨運行的類中,它們將調(diào)用沖突 jar 包的功能,并將結(jié)果以系統(tǒng)輸出的方式打印到系統(tǒng)標準輸出上。 將這些類封裝到一個單獨的 jar 文件中,比如 workAroundConflict.jar,并將其放在 was 可訪問的路徑上,比如 /usr/WebSphere/workAroundConflict.jar。


             1 Package com.ibm.test; 
             2 
             3  Import com.ibm.ConflictClass; 
             4 
             5  Public class WorkAround{ 
             6  Public static void main(String[] args){ 
             7     String param1=args[0]; 
             8     String returnStr=ConflictClass.exampleCall (); 
             9     System.out.println("<RTStr>"+returnStr+"</RTStr>"); 
            10     Return; 
            11  } 
            12  }

            代碼 3:將對沖突代碼的調(diào)用寫入一個單獨的類 WorkAround
          • 步驟三:在 Web 模塊中通過命令行方式調(diào)用封裝的類,通過 classpath 指定所有依賴的 jar 包和類路徑。運行封裝類,從系統(tǒng)標準輸出中取得運行結(jié)果。


             1 Public static String methodA (String param){ 
             2     ……
             3     String rtStr = ""
             4     String lStr="<RTStr>"
             5     String rStr="<RTStr>"
             6     //put all the dependency jar here 
             7     String classPath=
             8     "/usr/WebSphere/conflict_v2.jar; 
             9     /usr/WebSphere/workaroundConflict.jar; ……"
            10     String className="com.ibm.test.WorkAround"
            11     String cmdLine="java -classpath " +classPath +" " +className + " "+ param; 
            12     Try{ 
            13         Process process = Runtime.getRuntime().exec(cmdLine,null); 
            14         process.waitFor(); 
            15         BufferedReader br= new BufferedReader( 
            16                   new InputStreamReader(process.getInputStream())); 
            17         while ((s = br.readLine())!=null) { 
            18             if (null == out) 
            19                 out=s; 
            20             else 
            21                 out+=s; 
            22  } 
            23  //get result from out 
            24  if (null != out){ 
            25     int lIndex = out.lastIndexOf(lStr); 
            26     int rIndex = out.lastIndexOf(rStr); 
            27     rsStr = out.substring(lIndex+lStr.length, rIndex); 
            28  } 
            29 
            30     } catch (Exception e){ 
            31         e.printStackTrace(); 
            32  } 
            33 …… . 
            34  return rsStr; 
            35  }

            代碼 4:在應(yīng)用程序中通過命令行方式運行 WorkAround

          命令行運行方式通過啟動另外一個 JVM 的方式運行沖突代碼,在一個不同的 JVM 中加載沖突的類,從而解決了 jar 包沖突問題。

          但是命令行運行方式畢竟不是一個很好的方式,它存在以下的弊端:

          • 命令行運行方式只適用于對沖突 jar 包的使用只是運行一段代碼,或者只要求返回簡單的字符串結(jié)果的情況。對于復(fù)雜的交互,命令行方式無法做到。但是如果在別無他法的情況下,可以適當(dāng)?shù)貏澐址?裝對沖突代碼調(diào)用的 jar 包的包含范圍,盡量將命令行運行的代碼接口簡單化。
          • 命令行運行方式因為啟動了另外一個 JVM 來運行,降低了 WebSphere 的性能。

          因此,命令行方式只適用于一些極為特殊的情況下解決 jar 包沖突問題。

          回頁首

          結(jié)論

          本文對基于 WebSphere 的大型項目開發(fā)中遇到的 jar 包沖突問題,結(jié)合 WebSphere 中類加載器的概念,給出了三種解決辦法以及相應(yīng)的操作步驟和實現(xiàn)代碼,并分析了各種方式所適用的具體情況。

          項目開發(fā)過程中的 jar 包沖突,主要存在以下三種情況:

          • 多個應(yīng)用程序間的 jar 包沖突
          • 應(yīng)用程序內(nèi)多個 Web 模塊間的 jar 包沖突
          • 應(yīng)用程序內(nèi)同一個 Web 模塊內(nèi)部 jar 包沖突

          通過對類加載器的分析我們知道,解決 jar 包沖突問題的根本在于合理配置類加載器。在深入理解 WebSphere 中類加載器的層次結(jié)構(gòu)的基礎(chǔ)上,我們給出了"共享庫解決 jar 包沖突"以及"打包到 Web 模塊中解決 jar 包沖突"的辦法,通過合理地配置 WebSphere 中類加載器及其委托模式,可以解決大多數(shù)的 jar 包沖突問題。但是由于這個層次結(jié)構(gòu)中類加載器只配置到 Web 模塊,因此,對于 Web 模塊內(nèi)部的 jar 包沖突問題,類加載器的配置是無法解決的,為此我們給出了"命令行運行方式解決 jar 包沖突"的辦法。

          表 2 中列出了在不同的 WAS 版本下,三種解決 jar 包沖突問題的辦法所適用的 jar 包沖突情況。


          表 2:Jar 包沖突解決辦法適用的 jar 包沖突情況總結(jié)
          表 2:Jar 包沖突解決辦法適用的 jar 包沖突情況總結(jié)

          參考資料

          • IBM WebSphere Application Server V5 ClassloaderNamingSpace Guide。

          • IBM WebSphere Application Server V5.1 System Management and Configuration。

          作者簡介

          郝愛麗是一位 IBM CSDL 的軟件工程師,從事多年 J2EE 開發(fā)工作,有豐富的 J2EE 開發(fā)經(jīng)驗。目前從事企業(yè)電子商務(wù)應(yīng)用的開發(fā)和支持。

          常紅平是一位 IBM CSDL 的軟件工程師,IBM certified DB2 DBA 和 IBM certified DB2 developer。他目前正在從事企業(yè)電子商務(wù)應(yīng)用的開發(fā)。您可以通過 changhp@cn.ibm.com 和他聯(lián)系。


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 富阳市| 西昌市| 鄢陵县| 四川省| 清丰县| 南雄市| 百色市| 湖北省| 淳安县| 普兰店市| 桐乡市| 建阳市| 玉环县| 辰溪县| 岚皋县| 雷波县| 万宁市| 淄博市| 保德县| 易门县| 桐柏县| 湖州市| 广平县| 泾阳县| 额济纳旗| 玉树县| 辽阳县| 娄烦县| 许昌市| 峨山| 绥中县| 南丰县| 上蔡县| 永靖县| 额尔古纳市| 玛沁县| 石柱| 三江| 麻江县| 洪湖市| 宁津县|