Tomcat虛拟主機同時運作多個使用 ImageMagick +Jmagick的網站,遇到了這個錯誤:Native Library C:\WINDOWS\system32\jmagick.dll already loaded in another classloader
-----------------------------------------------------
環境說明:
中間件:tomcat6.0.18
開發環境:winXP
伺服器:CentOS5.3
在一個tomcat下,有多個虛拟主機, 運作了多個網站,每個網站都使用 ImageMagick +Jmagick 來處理圖檔, 須要使用JNI調用本地*.dll檔案來處理圖檔, 每個網站(web應用程式)都有自己的lib,在WebContent\WEB-INF\lib下面. 這樣就有重複的jar包, 如jmagick.jar,servlet-api.jar, ***等好多jar包, 在每個網站(web應用程式)都有一份.
-----------------------------------------------------
結果在啟動tomcat時會報:
1 忽略了servlet-api.jar . (具體日志資訊沒有複制)
2 一個web應用程式處理完圖檔後,第二個web應用程式再處理圖檔時會出錯:Native Library C:\WINDOWS\system32\jmagick.dll already loaded in another classloader
3 A C3P0Registry mbean is already registered
-----------------------------------------------------
我搜尋到了 http://jbossweek.iteye.com/blog/138903的一篇文章:
1、症狀
如果JBoss上的兩個web應用需要使用相同的JNI本地庫,當第二個web應用加載JNI本地庫時,就會出現Native Library xxx.so already loaded in another classloader錯誤
2、原因
Java虛拟機為了在JNI本地庫中確定基于classloader的命名空間隔離,因而不允許一個JNI本地庫被兩個不同的classloader加載。而JBoss中web應用的classloader是獨立的,也就是說每個web應用都有一個專屬的classloader,這樣就出現兩個classloader加載同一JNI本地庫的情況
3、解決方法
在JBoss AS中,雖然不同的web應用使用不同的classloader,但是web應用classloader的父classloader是相同的,這樣根據雙親委托模型隻要讓父classloader加載JNI本地庫就可以避免被多個classloader加載。父classloader的classpath為JBoss AS配置(default、all或minimal)的lib目錄,因而隻要将JNI class單獨釋出成jar包,并放在配置(default、all或minimal)的lib目錄中,問題就可以解決
以上說明了問題的原因, 上面說 "因而隻要将JNI class單獨釋出成jar包" , 我使用了 jmagick.jar是在這裡調用了JNI , 是以把jmagick.jar 從WebContent\WEB-INF\lib下 移動到了E:\tomcat-6.0.18\lib下, 就不會被重複加載了.
----------------------------------------------------
Tomcat6的類加載順序:
1、最先是$JAVA_HOME/jre/lib/ext/下的jar檔案。
2、環境變量CLASSPATH中的jar和class檔案。
3、$CATALINA_HOME/lib 下的jar檔案。
4、各自具體的webapp /WEB-INF/classes下的class檔案。
5、各自具體的webapp /WEB-INF/lib下的jar檔案。