Log4j做爲日誌組件被大多數的系統所使用,Jboss也不例外的採用了Log4j做爲它的日誌輸出組件。java
但在使用JBoss時,不少人常常碰到一些衝突,這些衝如本身配置的log4j文件無效,系統拋org.jboss.logging.util.OnlyOnceErrorHandlerobject is not assignable to a orweb
g.apache.log4j.spi.ErrorHandler variable異常等。爲了解決形成這方面的緣由,咱們須要分析Jboss和log4j的一些關係。本文的下面內提供了一個最佳的配置及對問題的分析,在理解了下面的內容後,相信你們都能解決log4j的衝突問題,並找到符合本身的一種解決方法。apache
1、最佳無衝突配置tomcat
解決jboss和log4j衝突的最理想配置以下:服務器
配置jboss_server_home/deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml文件裏的Java2ClassLoadingCompliance及UseJBossWebLoader爲false,若是存在WEB-INF/jboss-web.xml,則裏面的java2ClassLoadingCompliance及java2ParentDelegaton屬性也都設置成false。在webapp裏log4j的配置文件採用xml形式,並命名爲log4j.xml,同時在webapp的lib裏須要包含log4j相關的jar包,經過這樣的配置後,webapp的log4j和jboss的log4j將相互隔離互不影響。app
2、Log4j載入配置文件的方式webapp
Log4j在查找它的配置文件的時候,默認狀況下,首先會在Classloader裏查找log4j.xml文件,第一個找到的文件做爲它的配置,在找不到log4j.xml文件的狀況下,再查找log4j.properties文件,找到則使用這個文件,沒有找到則報錯。url
3、JBoss和Log4j的關係:spa
關於JBoss啓動和ClassLoader模型的關係,請參見:.net
http://blog.csdn.net/youfly/archive/2009/02/12/3884081.aspx
爲了更好的理解下面的內容,若是對JBoss的啓動過程和ClassLoader模型不太清楚的話,請先閱讀上面的文章。
下圖是jbossclassloader和相關的log4j配置文件
Jboss classloader及相關的log4j的配置文件
4、JBoss啓動初始化階段
JBoss第一次使用Log4j是在JBoss Server實例初始化的時候,也即調用server.init(props)方法的時候,在這個時候JBoss線程的TCL(Thread Context ClassLoader)是NoAnotationURLClassLoader,且Server實例的定義ClassLoader也是NoAnotationURLClassLoader。所以init方法是在NoAnotataionURLClassLoader的上下文中執行,在執行時,全部的類及相關的資源文件都經過NoAnotatationURLClassLoader來裝載。根據JBoss的ClassLoader模型,該ClassLoader能夠載入jboss_home/lib目錄下的一些jar包及bin/run.jar,具體請參考上面的文章,但它不能訪問jboss_server_home/conf目錄,因此這個時候沒有辦法訪問jboss_server_home/conf/log4j.xml文件。在第一次使用Log4j時,Log4j會進行初始化,初始化時它首先查找log4j.xml文件,根據ClassLoader的委派模型,它會委派載入log4j.xml資源的請求給SystemClassLoader,這個時候若是sytem classpath裏存在log4j.xml文件,Log4j將使用那個文件,若是不存在,則由NoAnotationURLClassLoader本身嘗載入,它發現本身也載入不了。Log4j發現找不到log4j.xml文件後,會嘗載入log4j.propertes文件,和載入xml文件時相似,它也首先進行委派載入,同理若是systemclasspath裏存在log4j.properties文件,Jboss將使用system classpath裏包含的文件,若是不存在NoAnotationURLClassLoader嘗試本身進行載入,它能夠從jboss_home/bin/run.jar裏找到log4j.properties文件。run.jar包裏包含的log4j.properties將JBoss內核初始化啓動的調試日誌輸入到jboss_server_home/log/boot.log文件的定義。所以能夠推斷,若是在system classpath裏包含log4j.xml或者log4j.properties可能會致使boot.log不能正確的寫入,但不會出現什麼異常。
5、JBoss部署階段
Jboss使用Log4j的第二部分是在進行部署的時候,包括SAR,EAR,Jar,EJB……部署。jboss_server_home/conf/jboss-service.xml裏配置的log4jService這個MBean service先對log4j進行一個初始化,在默認的配置中,log4j所用的配置文件是classpath裏的log4j.xml。在log4j service初始化前,JBoss的全部日誌經過都會寫到boot.log中。在SARDeployer處理好jboss_server_home/conf/jboss-service.xml文件,並初始化好log4j.xml後,一般jboss的日誌就會寫入到server.log中。SARDeployer在初始化log4j service的時候,JBoss的線程TCL爲包含patchDir(它由jboss.patch.url屬性指定)和服務器conf目錄的UCL。在服務器目錄conf裏包含一個log4j.xml文件。所以在log4j service初始化的時候一般使用conf目錄下的log4j.xml(即jboss_server_home/conf/log4j.xml),但若是在system classpath包含有一個log4j.xml的話,jboss在初始化log4j時將會使用system clapsspath裏的log4j.xml。這會致使server.log不正常的寫入,日誌的級別及寫入的文件受system classpath裏的log4j.xml影響。
6、web應用啓動並服務階段
第三部分的log4j相關的部分應該就是咱們應用開發裏用到的log4j。這裏只討論Webapp的開發。根據JBoss的ClassLoader結構,在默認配置狀況下,Webapp所用的ClassLoader是org.jboss.web.tomcat.tc5.WebAppClassLoader。它默認的class載入方式是先檢查本身能不能載入請求的類(對於jdk核心的API則也是先請求父類載入),若是不能載入再請求父ClassLoader載入。這個行爲能夠經過jboss_server_home/deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml配置文件裏的Java2ClassLoadingCompliance屬性進行修改,若是這個屬性爲true,則首先檢查父類能不能載入,而後再檢查本身能不能載入,這個配置參數在JBossAS- 4.0.3 Final因爲bug問題沒有做用,bug參見:http://jira.jboss.com/jira/browse/JBAS-2347。固然它也能夠經過在WEB-IN/jboss-web.xml這個文件裏進行配置
<class-loading java2ClassLoadingCompliance='true'>
<loader-repository>
dot.com:loader=unique-archive-name
<loader-repository-config>
java2ParentDelegaton=true
</loader-repository-config>
</loader-repository>
</class-loading>
或
<class-loadingjava2ClassLoadingCompliance='true'> </class-loading>
對於上一種配置,webapp將使用JBoss 隔離的UCL做爲Classloader,而且是不是parent load模型是由其中的java2ParentDelegaton參數決定,java2ClassLoadingCompliance='true'屬性將被忽略。對於第二次狀況用的是org.jboss.web.tomcat.tc5.WebAppClassLoader,java2ClassLoadingCompliance='true'或者'false'決定了是否採用parent first模型。咱們如今來分析log4j在這裏面的初始化。若是咱們在web應用裏對log4j進行手動的初始化,而且初始化的配置文件沒有和JBoss自己的配置文件衝突的話(如配置文件不要使用log4j.properties或log4j.xml),通常log4j仍是能正常工做的。若是沒有本身進行初始化,則採用了log4j默認的初始化流程,即首先查找log4j.xml再查找log4j.properties的方式。在webapp裏調用log4j的時候,它的TCL是WebAppClassLoader,所以初始化時,首先會要求WebAppClassLoader載入log4j相關的類,在沒有配置java2ClassLoadingCompliance或者java2ClassLoadingCompliance='false'的狀況下。
1. 若是webapp裏存在log4j的類庫,WebAppClassLoader會載入該類庫,因爲在WebAppClassLoader裏是第一次載入該類庫,所以他們對log4j進行默認的初始化,它首先查找log4j.xml。
l若是在webapp相關的classpath可以找到這個文件,則用這個文件進行初始化。
l 不然找到委派給父Classloader進行查找,父ClassLoader UCL能夠找到jboss_server_home/conf/log4j.xml文件,所以webapp相關的日誌級別及輸出文件都根據那個配置文件指定的規則來進行(默認配置輸出到jboss_server_home/log/server.log),但在這種狀況下,每每會出現相似於下面的異常。
2008-01-22 18:43:15,868 ERROR [STDERR] log4j:ERROR A"org.jboss.logging.util.OnlyOnceErrorHandler" object is notassignable to a "or
g.apache.log4j.spi.ErrorHandler" variable.
2008-01-22 18:43:15,868 ERROR [STDERR] log4j:ERROR The class"org.apache.log4j.spi.ErrorHandler" was loaded by
2008-01-22 18:43:15,868 ERROR [STDERR] log4j:ERROR[WebappClassLoader
delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader:
java.net.FactoryURLClassLoader@18bea70
] whereas object of type
2008-01-22 18:43:15,868 ERROR [STDERR] log4j:ERROR"org.jboss.logging.util.OnlyOnceErrorHandler" was loaded by[org.jboss.system.ser
ver.NoAnnotationURLClassLoader@ 1c 9a 690].
2008-01-22 18:43:15,923 ERROR [STDERR] log4j:ERROR Could not createan Appender. Reported error follows.
2008-01-22 18:43:15,923 ERROR [STDERR] java.lang.ClassCastException:org.jboss.logging.appender.DailyRollingFileAppender
2008-01-22 18:43:15,924 ERROR [STDERR] atorg.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:175)
2008-01-22 18:43:15,925 ERROR [STDERR] atorg.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.java:150)。
……………………………………………………
出現這個異常的緣由是org.jboss.logging.util.OnlyOnceErrorHandler這個類是由WebappClassLoader載入的(這是由於在webappp裏存在log4j的jar包,而當前採用了child first的載入模型),而org.jboss.logging.util.OnlyOnceErrorHandler這個類在Webapp裏不存在,所以它委派到了祖先ClassLoader NoAnnotationURLClassLoader來載入,NoAnnotationURLClassLoader可以載入該類,但類OnlyOnceErrorHandler的父類org.jboss.logging.util.OnlyOnceErrorHandler也是由NoAnnotationURLClassLoader載入的,它不能轉化爲由WebAppClassLoader載入的org.jboss.logging.util.OnlyOnceErrorHandler類型的對象,兩個定義ClassLoader不一致。
2. 若是在webapp裏不存在log4j的類庫,log4j的相關類就是JBoss初始化log4j service時載入的類,這個時候webapp不在從新初始化log4j(由於JBoss已對log4j進行了初始化),使用了jboss log4j service初始化的配置。
java2ClassLoadingCompliance=’true’的狀況下,webapp使用的log4j和java2ClassLoadingCompliance=’false’的第二種狀況一致,再也不詳述。
若是jboss_server_home/deploy/jbossweb-tomcat55.sar/META-INF/jboss-service.xml文件裏配置UseJBossWebLoader爲true。因爲JBoss採用了一個共享的扁平的UCL,webapp裏包含的log4j.properties及log4j.xml文件通常都不會被使用,緣由是JBoss初始化的log4j service更具優先級。爲了使用webapp裏的配置文件,咱們須要配置webapp裏的log4j配置文件到system classpath中,這個時候不論是log4j.properties仍是log4j.xml,都能被初始化,但會覆蓋掉JBoss自己一些日誌配置,若是是log4j.properites文件,則會覆蓋boot.log日誌,若是是log4j.xml,則boot.log及server.log都會被覆蓋,具體緣由能夠從前面的章節找到。
轉載請註明出處: www.jfuns.com www.jfuns.cn http://blog.csdn.net/youfly