12.5.2 步驟 2:添加一個EJB模塊和工具JAR
下面,往應用程序中添加一個EJB,它也依賴VersionChecker JAR文件。在此,在EAR的根目錄添加一個VersionCheckerV2.jar 文件。在這個JAR文件中的VersionChecker 類返回了Version 2.0。爲了保證擴展類加載中的工具JAR可用,在EJB模塊的manifest文件中添加一個引用,如例12-8:
例12-8 更新EJB模塊的 MANIFEST.MF 文件
Manifest-Version: 1.0
Class-Path: VersionCheckerV2.jar
現在的結果是:有一個Web模塊,在它的WEB-INF/classes 目錄下面有一個servlet,在WEB-INF/lib 目錄下面有VersionCheckerV1.jar 文件。還有一個EJB模塊引用了EAR根目錄下面的VersionCheckerV2.jar 工具JAR。你期望Web模塊裝入VersionChecker 類文件的版本是什麼?是WEB-INF/lib 下的Version 1.0 還是工具JAR下面的Version 2.0?測試結果如例12-9:
例12-9 類加載 例2
VersionChecker called from Servlet
VersionChecker is v2.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@26282628
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleEJB.jar;C:\WebSphere\AppServ
er\profiles\AppSrv02\installedApps\kcgg1d8Node02Cell\ClassloaderExample
.ear\VersionCheckerV2.jar
Delegation Mode: PARENT_FIRST
VersionChecker called from EJB
VersionChecker is v2.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@26282628
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel l\ClassloaderExample.ear\ClassloaderExampleEJB.jar;C:\WebSphere\AppServ
er\profiles\AppSrv02\installedApps\kcgg1d8Node02Cell\ClassloaderExample
.ear\VersionCheckerV2.jar
Delegation Mode: PARENT_FIRST
正如所看到的,當同時調用EJB模塊和Web模塊,VersionChecker 是 Version 2.0 。當然,原因是:WAR類加載器將請求委託給了父類加載器而不是他自己,所以工具JAR就被同一個類加載器加載,而無需考慮請求是來自於servlet還是EJB。
12.5.3 步驟 3:改變WAR類加載的委託模式
現在是否希望Web模塊使用WEB-INF/lib 目錄下面的VersionCheckerV1.jar 文件?爲了這個目的,需要先將類加載委託模式從parent first 改爲parent last。
設置委託模式爲PARENT_LAST,使用如下步驟:
1. 在嚮導欄選擇Enterprise Applications;
2. 選擇ClassloaderExample 應用程序;
3. 在模塊部分選擇Manage modules ;
4. 選擇ClassloaderExampleWeb 模塊;
5. 將類加載順序修改成應用程序類加載優先(PARENT_LAST)。記住,這個條目應該稱爲WAR類加載優先,參見 “類加載/委託模式”;
6. 單擊 OK.
7. 保存配置;
8. 重新啓動應用程序。
WEB-INF/lib 下的VersionCheckerV1 返回version of 1.0。可以在例12-10中看到:
例12-10 類加載 例3
VersionChecker called from Servlet
VersionChecker is v1.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@4d404d40
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\classes;C:\W
ebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cell\Cl
assloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\lib\VersionCheck
erV1.jar;C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8
Node02Cell\ClassloaderExample.ear\ClassloaderExampleWeb.war
Delegation Mode: PARENT_LAST
VersionChecker called from EJB
VersionChecker is v2.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@37f437f4
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleEJB.jar;C:\WebSphere\AppServ
er\profiles\AppSrv02\installedApps \kcgg1d8Node02Cell\ClassloaderExample
.ear\VersionCheckerV2.jar
Delegation Mode: PARENT_FIRST
如果你使用類加載器的搜索功能,搜索*VersionChecker*,會得到圖12-9:
圖12-9 類加載查看器搜索功能
例12-11 顯示源代碼
例12-11 類加載查看器搜索功能
WAS Module Compound Class Loader (WAR class loader):
file: / C: / WebSphere / AppServer / profiles / AppSrv02 /
installedApps / kcgg1d8Node02Cell / ClassloaderExample.ear /
ClassloaderExampleWeb.war / WEB-INF / lib / VersionCheckerV1.jar
WAS Module Jar Class Loader (Application class loader):
file: / C: / WebSphere / AppServer / profiles / AppSrv02 /
installedApps / kcgg1d8Node02Cell / ClassloaderExample.ear /
VersionCheckerV2.jar
12.5.4 步驟 4:使用共享庫共享工具JAR
在此之前,只有一個應用程序使用VersionCheckerV2.jar 文件。是否希望多個應用程序能夠共享它?當然,你可以在每個EAR文件中把這個文件打包進去。但是如果需要修改這個工具JAR,那需要重新部署所有的應用程序。爲了避免這個麻煩,你可以使用共享庫全局共享這個JAR文件。
共享庫可以定義在單元、節點、應用程序服務器和集羣。一旦你定義了共享庫,必須將它跟應用程序服務器的類加載器或者單獨的Web模塊關聯起來。根據共享庫指派的目的地不同,WebSphere會使用匹配的類加載器加載共享庫。
只要願意,可以定義多個共享庫。也可以爲應用程序、Web模塊或者應用程序服務器指派多個共享庫。
在應用程序級別使用共享庫
定義一個名爲VersionCheckerV2_SharedLib 的共享庫,並把它跟ClassloaderTest 應用程序關聯起來,步驟如下:
1. 在管理控制檯,選擇Environment → Shared Libraries;
2. 選擇共享庫的作用域,比如單元,單擊New;
3. 如圖12-10:
圖 12-10 共享庫配置
– Name: 輸入VersionCheckerV2_SharedLib;
– Class path: 輸入類路徑中的條目,每個條目之間用回車隔開。如果提供絕對路徑,建議是用WebSphere環境變量,比如 %FRAMEWORK_JARS%/VersionCheckerV2.jar ,確定你已經定義了一個和共享庫相同作用域的變量。
– Native library path: 輸入JNI代碼使用的DLLs 和.so 文件列表。
4. 單擊 OK;
5. 選擇 Applications → Enterprise Applications;
6. 選擇應用程序 ClassloadersExample ;
7. 在引用選項,選擇 Shared library references ;
8. 在應用程序列選擇 ClassloaderExample ;
9. 單擊 Reference shared libraries;
10. 選擇 VersionCheckerV2_SharedLib ,單擊 >> 按鈕將選中的移動到 Selected 列,如下圖12-11:
圖12-11 指定一個共享庫
11. 單擊OK ;
12. ClassloaderExample 應用程序共享庫配置窗口如下圖12-12:
圖12-12 將共享庫指派給應用程序 ClassloaderExample
13. 單擊OK ,保存配置。
如果我們現在從EAR文件的根目錄將VersionCheckerV2.jar刪除,在EJB模塊的manifest文件中也把引用刪除,重新啓動應用服務器,看到例12-12的結果。記住,Web模塊的類加載順序依然是應用程序類加載優先(PARENT_LAST)。
例12-12 類加載 例4
VersionChecker called from Servlet
VersionChecker is v1.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@2e602e60
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\classes;C:\W
ebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cell\Cl
assloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\lib\VersionCheck
erV1.jar;C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8
Node02Cell\ClassloaderExample.ear\ClassloaderExampleWeb.war
Delegation Mode: PARENT_LAST
VersionChecker called from EJB
VersionChecker is v2.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@19141914
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleEJB.jar;C:\henrik\VersionChe
ckerV2.jar
Delegation Mode: PARENT_FIRST
正如預料的,由於Web模塊的委託模式,當servlet 需要VersionChecker 類,VersionCheckerV1.jar 文件被加載。當EJB需要VersionChecker 的類的時候,就會從指向C:\henrik\VersionCheckerV2.jar 的共享庫中加載它。如果你希望Web模塊也使用共享庫,只需要將類加載順序恢復成缺省值,Web模塊的類加載是父類加載優先。
在應用程序服務器級別使用共享庫
共享庫也可以跟應用程序服務器關聯起來。在這個服務器上的部署的所有應用程序都能夠看到共享庫的代碼列表。要把共享庫跟應用程序服務器關聯起來,首先要爲應用程序服務器創建一個附加的類加載器,步驟如下:
1. 選擇應用程序服務器;
2. 在應用程序基礎結構部分,展開 Java and Process Management,選擇 Class loader;
3. 選擇New,爲這個類加載器選擇類加載順序,父類加載優先 (PARENT_FIRST) 或者應用程序類加載優先 (PARENT_LAST),單擊 Apply;
4. 單擊剛剛創建的類加載器;
5. 單擊 Shared library references;
6. 單擊 Add,選擇希望跟應用程序服務器關聯的庫。重複選擇操作,將多個庫跟這個類加載器關聯。比如選擇 VersionCheckerV2_SharedLib 條目;
7. 單擊 OK;
8. 保存配置;
9. 重新啓動應用程序服務器,修改纔會生效。
將VersionCheckerV2 共享庫跟應用程序服務器關聯起來,就得到例12-13的結果。
例12-13 類加載 例5
VersionChecker called from Servlet
VersionChecker is v1.0.
Loaded bycom.ibm.ws.classloader.CompoundClassLoader@40c240c2
Local ClassPath:
C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cel
l\ClassloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\classes;C:\W
ebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8Node02Cell\Cl
assloaderExample.ear\ClassloaderExampleWeb.war\WEB-INF\lib\VersionCheck
erV1.jar;C:\WebSphere\AppServer\profiles\AppSrv02\installedApps\kcgg1d8
Node02Cell\ClassloaderExample.ear\ClassloaderExampleWeb.war
VersionChecker called from EJB
VersionChecker is v2.0.
Loaded bycom.ibm.ws.classloader.ExtJarClassLoader@7dee7dee
Local ClassPath: C:\henrik\VersionCheckerV2.jar
Delegation Mode: PARENT_FIRST
我們定義的新的名爲 ExtJarClassLoader 類加載器,在EJB模塊請求時,它裝入VersionCheckerV2.jar 文件。由於委託模式,WAR類加載器繼續裝入自己的version。
12.6 類加載器問題診斷
JVM 5.0提供了一些配置,可以讓我們查看詳細的類裝入,比如JVM 參數 -verbose:dynload、-Dibm.cl.verbose=<name>。
在實際開發過程中,如果使用不當,會出現很多類加載相關的問題。當遇到類加載問題時,可以查看WAS的相關日誌,在日誌中出現如下異常,可以認爲是類加載器出現了問題:
ClassCastException
ClassNotFoundException
NoClassDefFoundError
NoSuchMethodError
IllegalArgumentException
UnsatisfiedLinkError
VerifyError
關於問題診斷,將在下一篇文章《WAS 6.1 類加載問題診斷》詳細闡述。
總結
本文針對WAS6.1版本,詳細介紹了類加載的概念以及如何客戶化,並通過幾個例子向大家講述了影響類加載的選項的使用。雖然WAS 6.1 允許根據需要修改類加載策略,比如將父類優先改成應用程序優先,但是不推薦這麼使用。筆者曾經就遇到因爲修改策略,導致應用程序無法啓動。原因是WAS中的組件和應用程序使用的某些類是一致的,加載策略選擇不正確,就會導致類加載錯誤。
參考資料
1.WebSphere Application Server V6.1: System Management and Configuration
http://www.redbooks.ibm.com/abstracts/sg247304.html?Open
2.WebSphere Application Server V6.1: Classloader Problem Determination
http://www.redbooks.ibm.com/abstracts/redp4307.html?Open
3.類裝入問題解密,第 1 部分: 類裝入和調試工具介紹
http://www.ibm.com/developerworks/cn/java/j-dclp1/
4.類裝入問題解密,第 2 部分: 基本的類裝入異常
http://www.ibm.com/developerworks/cn/java/j-dclp2.html
5.類裝入問題解密,第 3 部分: 處理更少見的類裝入問題
http://www.ibm.com/developerworks/cn/java/j-dclp3/
6.類裝入問題解密,第 4 部分: 死鎖和約束
http://www.ibm.com/developerworks/cn/java/j-dclp4/
7.J2EE 類裝入揭密
http://www.ibm.com/developerworks/cn/websphere/library/techarticles/0112_deboer/deboer.html
8.WAS 6.1 信息中心
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp
關於作者
胡偉紅,西安交通大學碩士,目前就職於IBM 軟件部。主要負責 WebShpere軟件產品的技術支持。可通過[email protected]與她聯繫。