<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    gbk

    Apache Commons Logging 是如何決定使用哪個日志實現類的

    Apache Commons Logging 像 SLF4J 一樣,是個通用日志框架,廣泛應用在各個開源組件中。說其通用,是因為它本身只提供了簡單的日志輸出的實現 (org.apache.commons.logging.impl.SimpleLog和 org.apache.commons.logging.impl.NoOpLog),主要是為你統一使用其他專業日志實現(Log4j、jdk1.4 Logger、aavalon-Logkit)的方式,讓你在程序中看不到具體日志實現的代碼,以配置方式解藕。

    那么 commons-logging 是怎么決定程序執行時該使用哪個具體的日志實現呢?這里 commons-logging 有兩個步驟要做:

    1. 定位 org.apache.commons.logging.LogFactory 的實現類(這一步是關鍵)
    2. 定位到的 LogFactory 實現類決定使用哪個 org.apache.commons.logging.Log 實現

    那現在我們把注意力主要集中在 commons-logging 如何定位 LogFactory 實現類上來。org.apche.commons.logging.LogFactory 是一個抽象類,所以需要一個 LogFactory 具體類。

    通常我們用使用 commons-logging 時是在代碼中聲明:

    Log log = LogFactory.getLog(UnmiTestLog.class);

    在 getLog() 中是通過 getFactory() 方法獲得具體的 LogFactory 實現類,究竟也體現在這個方法中,所以這里非常有必要把這個方法的代碼拉出來。下面是 commons-loggin1.0.3 的 LogFactory.getFactory() 代碼,在新版代碼定位 LogFactory 的邏輯是一樣的。

    1. public static LogFactory getFactory() throws LogConfigurationException {  
    2.   
    3.     // Identify the class loader we will be using  
    4.     // 找到應用自身所用的加載器  
    5.     //在 WAS 5.1 下是 com.ibm.ws.classloader.CompoundClassLoader  
    6.     ClassLoader contextClassLoader =     
    7.         (ClassLoader)AccessController.doPrivileged(  
    8.             new PrivilegedAction() {  
    9.                 public Object run() {  
    10.                     return getContextClassLoader();  
    11.                 }  
    12.             });  
    13.   
    14.   
    15.     // Return any previously registered factory for this class loader  
    16.     // 看看是否有緩存的與此類加載器關聯的 LogFactory 實例,有則返回  
    17.     LogFactory factory = getCachedFactory(contextClassLoader);  
    18.     if (factory != null)  
    19.         return factory;  
    20.   
    21.   
    22.     // Load properties file..  
    23.     // will be used one way or another in the end.  
    24.     // 加載應用的 Classpath 下的屬性文件 commons-logging.properties  
    25.     // FACTORY_PROPERTIES 常量值是 commons-logging.properties  
    26.     // commons-logging 一般在這個文件里指定 LogFactory 的實現類  
    27.     // 注意,它只是去加載這個屬性文件,并不馬上用里面配置的 LogFactory 類  
    28.     Properties props=null;  
    29.     try {  
    30.         InputStream stream = getResourceAsStream(contextClassLoader,  
    31.                                                  FACTORY_PROPERTIES);  
    32.   
    33.         if (stream != null) {  
    34.             props = new Properties();  
    35.             props.load(stream);  
    36.             stream.close();  
    37.         }  
    38.     } catch (IOException e) {  
    39.     } catch (SecurityException e) {  
    40.     }  
    41.   
    42.     /**** 從下面開始就是 commons-logging 按什么順找到 LogFactory 實現類 ****/  
    43.   
    44.     // First, try the system property  
    45.     // 1. 查找系統屬性 FACTORY_PROPERTY(org.apache.commons.logging.LogFactory)  
    46.     // 的值所對應的 LogFactory 實現類  
    47.       
    48.     try {  
    49.         String factoryClass = System.getProperty(FACTORY_PROPERTY);  
    50.         if (factoryClass != null) {  
    51.             factory = newFactory(factoryClass, contextClassLoader);  
    52.         }  
    53.     } catch (SecurityException e) {  
    54.         ;  // ignore  
    55.     }  
    56.   
    57.   
    58.     // Second, try to find a service by using the JDK1.3 jar  
    59.     // discovery mechanism. This will allow users to plug a logger  
    60.     // by just placing it in the lib/ directory of the webapp ( or in  
    61.     // CLASSPATH or equivalent ). This is similar with the second  
    62.     // step, except that it uses the (standard?) jdk1.3 location in the jar.  
    63.     // 2. 使用 JDK1.3 jar 的 Service Provider Interface(SPI) 類發現機制  
    64.     // 從配置文件 SERVICE_ID(META-INF/services/org.apache.commons.logging.LogFactory)  
    65.     // 的第一行讀取 LogFactory 的實現類名  
    66.     // 這個 META-INF 目錄可以是 WebRoot 的 META-INF,也可以是 classpath 下的 META-INF 目錄  
    67.   
    68.     if (factory == null) {  
    69.         try {  
    70.             InputStream is = getResourceAsStream(contextClassLoader,  
    71.                                                  SERVICE_ID);  
    72.   
    73.             if( is != null ) {  
    74.                 // This code is needed by EBCDIC and other strange systems.  
    75.                 // It's a fix for bugs reported in xerces  
    76.                 BufferedReader rd;  
    77.                 try {  
    78.                     rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));  
    79.                 } catch (java.io.UnsupportedEncodingException e) {  
    80.                     rd = new BufferedReader(new InputStreamReader(is));  
    81.                 }  
    82.                   
    83.                 String factoryClassName = rd.readLine();  
    84.                 rd.close();  
    85.                   
    86.                 if (factoryClassName != null &&  
    87.                     ! "".equals(factoryClassName)) {  
    88.                       
    89.                     factory= newFactory( factoryClassName, contextClassLoader );  
    90.                 }  
    91.             }  
    92.         } catch( Exception ex ) {  
    93.             ;  
    94.         }  
    95.     }  
    96.   
    97.   
    98.     // Third try a properties file.   
    99.     // If the properties file exists, it'll be read and the properties  
    100.     // used. IMHO ( costin ) System property and JDK1.3 jar service  
    101.     // should be enough for detecting the class name. The properties  
    102.     // should be used to set the attributes ( which may be specific to  
    103.     // the webapp, even if a default logger is set at JVM level by a  
    104.     // system property )  
    105.     // 3. 現在才輪到用前面加載的 commons-logging.properties 文件中的  
    106.     // FACTORY_PROPERTY(org.apache.commons.logging.LogFactory) 屬性指定的 LogFactory 實現類  
    107.   
    108.     if (factory == null  &&  props != null) {  
    109.         String factoryClass = props.getProperty(FACTORY_PROPERTY);  
    110.         if (factoryClass != null) {  
    111.             factory = newFactory(factoryClass, contextClassLoader);  
    112.         }  
    113.     }  
    114.   
    115.   
    116.     // Fourth, try the fallback implementation class  
    117.     // 4. 前面幾步沒有找到 LogFactory 的實現類或有異常的話就用默認的實現類  
    118.     // 即 LogFactory 為我們準備的 FACTORY_DEFAULT(org.apache.commons.logging.impl.LogFactoryImpl)  
    119.   
    120.     if (factory == null) {  
    121.         factory = newFactory(FACTORY_DEFAULT, LogFactory.class.getClassLoader());  
    122.     }  
    123.       
    124.     if (factory != null) {  
    125.         /** 
    126.          * Always cache using context class loader.. 
    127.          * 緩存所用的實現類,以后直接使用緩沖中的 LogFactory 實現類 
    128.          */  
    129.         cacheFactory(contextClassLoader, factory);  
    130.   
    131.         if( props!=null ) {  
    132.             Enumeration names = props.propertyNames();  
    133.             while (names.hasMoreElements()) {  
    134.                 String name = (String) names.nextElement();  
    135.                 String value = props.getProperty(name);  
    136.                 factory.setAttribute(name, value);  
    137.             }  
    138.         }  
    139.     }  
    140.       
    141.     return factory;  
    142. }  


    在代碼中,我已加上注釋,有緩存的 LogFactory 實現類,取緩存中的,注意緩存是與當前應用的類加載器關聯的。若緩存中沒有的話按 1、2、3、4 的順序來找,現在就來說說查找 LogFactory 的順序:


    1. 從系統屬性中查找鍵為 org.apache.commons.logging.LogFactory 的值作為 LogFactory 的實現類;卻通過 System.getProperty("org.apache.commons.logging.LogFactory") 獲得

    2.  使用 JDK1.3 jar 的 Service Provider Interface(SPI) 類發現機制,從配置文件 META-INF/services/org.apache.commons.logging.LogFactory 的的第一行讀取 LogFactory 的實現類名。這個 META-INF/services/org.apache.commons.logging.LogFactory 文件可以是某個 Web 應用的根目錄中;也可以在 classpath 下,如某個 Jar 包中,WebRoot/WEB-INF/classes 中等。這里需多加留心下 META-INF/services/org.apache.commons.logging.LogFactory 這個目錄層次及文件名。

    3.  在 Classpath 下的 commons-logging.properties 文件中的,找到 org.apache.commons.logging.LogFactory 屬性值作為 LogFactory 實現類

    4. 前面三步未找個 LogFactory 的實現類,或有任何異常的情況下,就用默認的實現類,即 LogFactory 為我們準備的 org.apache.commons.logging.impl.LogFactoryImpl



    明白了以上的順序,可以幫助我們理解和解決一些實際的問題,例如,為什么可以不用 commons-logging.properties 也是使用的 log4j 日志實現,部署在 WAS 下的應用 log4j 怎么就不能輸出日志了呢?

    一 般,某個具體的 LogFactory 類對應就會使用與其相應的 Logger 實現,如 Log4jFactory.getLog() 得到的是 Log4JLogger 實例,WAS 的 TrLogFactory.getLog() 返回的是 TrLog 實例。

    老師們教我們用 commons-logging 時也許會讓我們在 classpath 下放一個 commons-logging.properties 文件,并在這個文件中寫上一行:

    org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.Log4jFactory

    或者是這么兩行:

    org.apache.cmmons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
    org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger


    然 而我們基本都是用的 Log4j 來輸出日志,其實不管 commons-logging.properties 是第一種寫法還是第二種寫法都是多余的,回望 LogFactory.getFactory() 方法,還要再看看 org.apache.commons.logging.impl.LogFactoryImpl 的 getLogClassName() 方法便可知。

    LogFactory.getFactory() 在前面三步找不到 LogFactory 實現類時,就會用默認的 LogFactoryImpl,而默認的 LogFactoryImpl.getLog() 時,又會根據以下四個順序來決定返回什么 Log 實例,在 LogFactoryImpl.getLogClassName() 中體現了:

    1. commons-logging.properties 中的 org.apache.commons.logging.Log 指定的 Log 實現類
    2. Log4j 可用就用 org.apache.commons.logging.impl.Log4JLogger
    3. Jdk1.4 Logger 可用就用 org.apcache.commons.logging.impl.Jdk14Logger(JDK1.4 開始自帶)
    4. SimpleLog 可用就用 org.apache.commons.logging.impl.SimpleLog(commons-logging 自帶)

    所 以這就是為什么了,使用了 commons-logging 的框架類,只要扔個 log4j 的 jar,根本不用 commons-logging.properties 文件就會用 log4j 來輸出日志,當然 log4j 自己的配置文件 log4j.xml 或 log4j.properties 是需要的。

    那為什么在 Tomcat 或別的應用服務器中 log4j  能正常輸出日志,一放到 WAS 下卻不靈了呢?原因是在 $WAS_HOME/lib/ws-commons-logging.jar 中有個文件 commons-logging.properties,其中有一行 org.apache.commons.logging.LogFactory=com.ibm.ws.commons.logging.TrLogFactory, 雖然你的應用中可能也有一個 commons-logging.properties,可是很不幸,WAS  自己的 commons-logging.properties 優先了,原因是類加載器的委托機制在作用,所以最終 log4j 沒派上用場,被 com.ibm.ws.commons.logging.TrLog 取而代之了,解決辦法是要搶在它之前,比系統屬性中聲明 LogFactory 實現類,或是在 META-INF/services/org.apache.commons.logging.LogFactory 中指名 Log4jFactory 實現類名。

    以后在使用 commons-logging 通用日志框架時,若出現什么問應具體情況具體分析,相信都不會變離本篇中能解釋的情況。

    posted on 2009-05-15 10:45 百科 閱讀(642) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     

    My Links

    Blog Stats

    常用鏈接

    留言簿(2)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久久亚洲精品国产| 亚洲国产精品专区在线观看| 亚洲AV无码成人网站久久精品大| 免费人成再在线观看网站| 亚洲成?Ⅴ人在线观看无码| 羞羞漫画在线成人漫画阅读免费 | 噜噜噜亚洲色成人网站∨| 污污网站免费观看| 免费无码又黄又爽又刺激| 精品国产亚洲一区二区在线观看| 无码的免费不卡毛片视频| 18禁美女裸体免费网站 | 国产偷v国产偷v亚洲高清| 亚洲人成电影网站| 成人免费无码大片A毛片抽搐色欲| 亚洲一级黄色视频| 视频免费在线观看| 亚洲黄网在线观看| 女人18毛片a级毛片免费视频| 国产精品亚洲色图| 中国在线观看免费高清完整版| 亚洲熟妇AV乱码在线观看| 亚洲A∨午夜成人片精品网站| 久久久久久久久久免免费精品 | 国产亚洲美女精品久久久2020 | 亚洲综合自拍成人| 成年在线网站免费观看无广告| 国产成人亚洲毛片| 亚洲av综合色区| 24小时免费直播在线观看| 乱淫片免费影院观看| 亚洲成人动漫在线| 青青青青青青久久久免费观看| 人妻仑刮八A级毛片免费看| 亚洲av不卡一区二区三区| 免费看美女让人桶尿口| 国产黄在线播放免费观看| 亚洲成人一级电影| 亚洲美女在线国产| 老司机在线免费视频| 成人毛片100免费观看|