jacob.dll already loaded in another classloader

問題描述:
    我在一個Web應用中(server是resin-ee-2.1.4)使用jacob完成word文檔自動轉換成pdf 文檔的功能(詳見我另一篇日誌),爲了保證web應用的穩定性,我提供了resin每晚自動重啓的機制,方法是利用定時servlet修改 resin.conf文件。但是當web應用重啓後,jacob會報以下錯誤;
    Native Library C:/WINNT/system32/jacob.dll already loaded in another classloader
    java.lang.UnsatisfiedLinkError: Native Library C:/WINNT/system32/jacob.dll already loaded in another classloader
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1437)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1397)
    at java.lang.Runtime.loadLibrary0(Runtime.java:788)
    at java.lang.System.loadLibrary(System.java:832)
    at com.jacob.com.Variant.<clinit>(Variant.java)
    ……
    然後轉pdf的功能會徹底失效,直到手工重啓resin服務。

問題分析:
    經過查看jacob源代碼發現在Variant類中有一個靜態方法:
    static {
      System.loadLibrary("jacob";
    }
     而UnsatisfiedLinkError錯誤表明jacob.dll已經被JVM的ClassLoader load了。通過查閱資料發現 Web Server的自動重啓機制是產生這一問題的根源。當Resin重啓包含jacob的這個Web應用時,會因爲Variant類的語句而自動執行 jacob的加載。但重啓Web應用並不是重啓整個resin(即:上一次啓動的JVM仍然存在),也就是說jacob已經被加載過了,因此係統將拋出 UnsatisfiedLinkError錯誤。而當我們手工重啓resin時,則會將上一次啓動的JVM關閉並重新啓動,這時會正常加載jacob。

問題解決:
    Java API 表明:JVM只允許一個默認的ClassLoader來load native library,同時並不提供專門的API來unload一個 loaded native library,因此無法在我們的重啓Web應用的代碼中來手工清除已經load的jacob。爲此我們必須保證在重啓 Web應用時不再重複加載jacob,具體方法是:將jacob.jar包放到Web Server的公共lib文件夾中(如:.../resin-ee -2.1.4/lib/),而不是Web應用的lib中(如:.../WEB-INF/lib/)。經過測試,自動重啓Web應用後,問題不再出現。

後記:
   雖然問題已解決,但總感覺有些不爽,畢竟沒有從根源上解決。還希望看到此篇日誌的網友繼續研究,如果能找出unload loaded native library的方法,希望貼上來大家共享。  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章