也許你們看到這個題目的時候,會想,commons-logging對log4j作了很好的支持,爲何會找不到呢! java
可是我想告訴你們的事,今天因爲我對Tomcat下lib的理解不深,就出現了一個這樣讓人費解的現象:
前提:
1. classPath下配置了log4j.properties文件
操做:
1. org.apache.commons.logging.LogFactory.getLog(key)獲取的Log
2. 經過Log.getName(),發現是org.apache.commons.logging.impl.Jdk14Logger apache
因而,我在網上查找了一些資料,獲得了一致的觀點(來源:http://javacrazyer.iteye.com/blog/1135493):
(1).common-logging首先在CLASSPATH中查找commons-logging.properties文件。這個屬性文件至少定義org.apache.commons.logging.Log屬性,它的值應該是上述任意Log接口實現的完整限定名稱。若是找到 org.apache.commons.logging.Log屬相,則使用該屬相對應的日誌組件。結束髮現過程。
(2).若是上面的步驟失敗(文件不存在或屬相不存在),common-logging接着檢查系統屬性org.apache.commons.logging.Log。若是找到org.apache.commons.logging.Log系統屬性,則使用該系統屬性對應的日誌組件。結束髮現過程。
(3).若是找不到org.apache.commons.logging.Log系統屬性,common-logging接着在CLASSPATH中尋找log4j的類。若是找到了就假定應用要使用的是log4j。不過這時log4j自己的屬性仍要經過log4j.properties文件正確配置。結束髮現過程。
(4).若是上述查找均不能找到適當的Logging API,但應用程序正運行在JRE 1.4或更高版本上,則默認使用JRE 1.4的日誌記錄功能。結束髮現過程。
(5).最後,若是上述操做都失敗(JRE 版本也低於1.4),則應用將使用內建的SimpleLog。SimpleLog把全部日誌信息直接輸出到System.err。結束髮現過程。 app
可是,我明確的在classpath下配置了log4j信息,爲何我卻獲得的不是org.apache.commons.logging.impl.Log4jLogger呢?這件事,讓我從新查看了commons-logging的源碼。發現代碼相對簡單。
在org.apache.commons.logging.impl.LogFactoryImpl的Line162,發現了以下代碼: jsp
/** * The names of classes that will be tried (in order) as logging * adapters. Each class is expected to implement the Log interface, * and to throw NoClassDefFound or ExceptionInInitializerError when * loaded if the underlying logging library is not available. Any * other error indicates that the underlying logging library is available * but broken/unusable for some reason. */ private static final String[] classesToDiscover = { LOGGING_IMPL_LOG4J_LOGGER, "org.apache.commons.logging.impl.Jdk14Logger", "org.apache.commons.logging.impl.Jdk13LumberjackLogger", "org.apache.commons.logging.impl.SimpleLog" };
/** * <p>Construct (if necessary) and return a <code>Log</code> instance, * using the factory's current set of configuration attributes.</p> * * <p><strong>NOTE</strong> - Depending upon the implementation of * the <code>LogFactory</code> you are using, the <code>Log</code> * instance you are returned may or may not be local to the current * application, and may or may not be returned again on a subsequent * call with the same name argument.</p> * * @param name Logical name of the <code>Log</code> instance to be * returned (the meaning of this name is only known to the underlying * logging implementation that is being wrapped) * * @exception LogConfigurationException if a suitable <code>Log</code> * instance cannot be returned */ public Log getInstance(String name) throws LogConfigurationException { Log instance = (Log) instances.get(name); if (instance == null) { instance = newInstance(name); instances.put(name, instance); } return instance; }
從這裏,我找到了一個很關鍵的代碼,即newInstance(name)。經過這個方法,我很快的肯定到了另外的一個子方法:createLogFromClass,發現它原來是經過反射的方式檢驗Log4j是否存在的,即: 測試
Class c = Class.forName(logAdapterClassName, true, currentCL);
首先,我證實了Log4j確實在項目的classpath下。方法同加載Log4jLogger同樣,只須要經過Class.forName()便可驗證。(項目能正常加載) ui
至此:
肯定問題:因爲commons-logging.jar是存放在Tomcat下共享lib的,而log4j是存放在項目工程中。 this
關於:Tomcat下共享lib和項目中lib之間的關係,下一篇文章分析。今天研究一下。 spa