commons-logging中沒法尋找log4j

也許你們看到這個題目的時候,會想,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"
    };



從上面的代碼及說明,證明了網上資料的正確性。接下來,Line289 getInstance(string name)獲取Log方法:
/**
     * <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);



獲得上面的信息,我在項目中寫了一個測試jsp頁面,來加載
org.apache.commons.logging.impl. Log4jLogger
很是幸運的是,我獲得了一個幸運的異常500,提示我,沒法加載org/apache/log4j/Category。我查看了log4j.jar,並在其中找到了此類。爲何Log4jLogger沒法加載呢?

首先,我證實了Log4j確實在項目的classpath下。方法同加載Log4jLogger同樣,只須要經過Class.forName()便可驗證。(項目能正常加載) ui

至此:
肯定問題:因爲commons-logging.jar是存放在Tomcat下共享lib的,而log4j是存放在項目工程中。 this

關於:Tomcat下共享lib和項目中lib之間的關係,下一篇文章分析。今天研究一下。 spa

相關文章
相關標籤/搜索