log4j 多classloader重複載入配置問題解決
最近OneCoder在開發隔離任務執行的沙箱,用於隔離使用者不同任務間以及任務和框架本身執行程式碼的隔離和解決潛在的jar包衝突問題。
執行發現,隔離的任務正常執行,但是卻沒有任何日誌記錄。從控制檯可看到如下錯誤資訊:
log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
log4j:ERROR [[email protected]] whereas object of type
log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [WebappClassLoader
context:
delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader:
[email protected]
].
log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].
log4j:WARN No appenders could be found for logger (com.xxx.xxx.xxx).
log4j:WARN Please initialize the log4j system properly.
錯誤資訊很明顯,log4j被兩個不同的classloader初始化了兩遍結果包錯。這個問題不難解決,主要有兩種手段:
第一、增加配置,讓log4j忽略由不同的classloader的初始化這個問題。在log4j的配置檔案中增加
log4j.ignoreTCL=true
即可。在某些版本的log4j的錯誤資訊中,還會提到下面的網址:
http://logging.apache.org/log4j/1.2/faq.html,裡面有關注上面屬性的介紹。
第二、修改初始化log4j執行緒的classloader。由於log4j會用當前執行緒上下文中的classloader去初始化配置,所以在我的沙箱應用中,雖然log4j的jar是由URLClassLoader載入進來的,但是載入的執行緒還是在WebApp中的,還是WebApp的ClassLoader,所以會出現上面的提示資訊。因此,我們至要通過下面程式碼:
Thread.currentThread().setContextClassLoader(urlclassLoader);
將當前執行緒的上下文loader改為沙箱的ClassLoader即可。
兩種解決方式,你可以按需選擇了。