log日志框架和LocationAwareLogger問題


遇到了同樣的問題,

我的解決辦法是在pom.xml中增加如下配置,去除對於jcl-over-slf4j.jar的依賴。

    <exclusions>
                <exclusion>
                    <artifactId>jcl-over-slf4j</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>

 

順便轉載下大神解答:

轉載自:http://blog.csdn.net/xian00000/article/details/10013395

 

今天啟動tomcat服務失敗,碰到異常情況如下

java.lang.NoSuchMethodError: org.slf4j.spi.LocationAwareLogger.log(Lorg/slf4j/Marker;Ljava/lang/String;ILjava/lang/String;Ljava/lang/Throwable;)V
    at org.apache.commons.logging.impl.SLF4JLocationAwareLog.info(SLF4JLocationAwareLog.java:159)

 

 

Commons-log + log4j 這黃金搭檔一直以來都讓我們很省心,很好的完成了日志的需求。但是隨着技術的變更和對性能的追求,slf4j 和 logback 這對后起之秀的到來好像打破了原本很平靜的日志系統,頻繁的出現包沖突... 

       和平的日子不在了,讓我們一起來看看究竟發生了什么...

 

 

 

 

 

首先看看這些個包,特別是slf4j引入后就引入了一大堆包之后就有點懵了。

 


 

為什么commons-logging和jcl-over-slf4j會有沖突呢?看一下它們的類結構

 


 

很清晰的可以看到jcl-over-slf4j 重寫了 commons-logging...

 

 

 

還有slf4j-api的實現呢,同樣看類:

 

 

其實就這么簡單,往往看了代碼之后才發現錯誤是這么顯而易見。。。

 

 

 

 

 

順着研究,繼續看一下slf4j的源碼及流程

 

1.測試類

 java代碼

[java] view plain copy
  1. package com.taobao.wuzhong.log;  
  2.   
  3. import org.apache.commons.logging.Log;  
  4. import org.apache.commons.logging.LogFactory;  
  5. import org.junit.Test;  
  6. import org.slf4j.Logger;  
  7. import org.slf4j.LoggerFactory;  
  8.   
  9. /** 
  10.  * DESC: 
  11.  *  
  12.  * Copyright: Copyright 2011 m.taobao.com 
  13.  *  
  14.  * @author wuzhong@taobao.com 
  15.  * @time 2011-4-6 下午03:42:11 
  16.  * @version 1.0 
  17.  **/  
  18. public class LogTest {  
  19.   
  20.     // Logback tries to find a file called logback.groovy in the classpath.  
  21.     // If no such file is found, logback tries to find a file called  
  22.     // logback-test.xml in the classpath.  
  23.     // If no such file is found, it checks for the file logback.xml in the  
  24.     // classpath..  
  25.     // If neither file is found, logback configures itself automatically using  
  26.     // the BasicConfigurator which will cause logging output to be directed to  
  27.     // the console.  
  28.     @Test  
  29.     public void test() {  
  30.                 //commons-logging的方式獲取  
  31.         Log log = LogFactory.getLog(LogTest.class);  
  32.                 //slf4j直接的方式獲取,推薦用這個  
  33.         Logger log2 = LoggerFactory.getLogger(LogTest.class);  
  34.         log.debug("eeeeee {} {} {}");  
  35.         log2.debug("{} {} {}", new String[] { "a", "b", "c" });  
  36.     }  
  37.   
  38. }  

logFactory.getLog 會調用內部靜態變量 Slf4jLogFactory.getInstance方法,如下:

 

 public Log getInstance(String name) throws LogConfigurationException {

[java] view plain copy
  1. Log instance = null;    
  2. // protect against concurrent access of loggerMap    
  3. synchronized (this) {    
  4.   instance = (Log) loggerMap.get(name);    
  5.   if (instance == null) {    
  6.     Logger logger = LoggerFactory.getLogger(name);   //slf4j的方式,代理過去了    
  7.     if(logger instanceof LocationAwareLogger) {    
  8.       instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger);  //包裝了一層,做適配    
  9.     } else {    
  10.       instance = new SLF4JLog(logger);    
  11.     }    
  12.     loggerMap.put(name, instance);    
  13.   }    
  14. }    
  15. return (instance);    


 

loggerFactory 會調用getILoggerFactory().getlOgger()

[java] view plain copy
  1. LoggerFactory.java    
  2.  public static ILoggerFactory getILoggerFactory() {    
  3.     if (INITIALIZATION_STATE == UNINITIALIZED) {    
  4.       INITIALIZATION_STATE = ONGOING_INITILIZATION;    
  5.       performInitialization();    
  6.     
  7.     }    
  8.     switch (INITIALIZATION_STATE) {    
  9.     case SUCCESSFUL_INITILIZATION:    
  10.       return getSingleton().getLoggerFactory();    
  11.     case FAILED_INITILIZATION:    
  12.       throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);    
  13.     case ONGOING_INITILIZATION:    
  14.       // support re-entrant behavior.    
  15.       // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106    
  16.       return TEMP_FACTORY;    
  17.     }    
  18.     throw new IllegalStateException("Unreachable code");    
  19.   }    
  20.     
  21.  private final static void performInitialization() {    
  22.     bind();    
  23.     versionSanityCheck();    
  24.     singleImplementationSanityCheck();    
  25.     
  26.   }    

這里的bind很關鍵,這里動態的綁定了slf4j-api的實現機制

 

[java] view plain copy
  1. static {    
  2.     SINGLETON.init();    
  3.   }    
  4.     
  5.   /**  
  6.    * Package access for testing purposes.  
  7.    */    
  8.   void init() {    
  9.     try {    
  10.       try {    
  11.         new ContextInitializer(defaultLoggerContext).autoConfig();    
  12.       } catch (JoranException je) {    
  13.         Util.reportFailure("Failed to auto configure default logger context",    
  14.             je);    
  15.       }    
  16.       StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);    
  17.       contextSelectorBinder.init(defaultLoggerContext, KEY);    
  18.       initialized = true;    
  19.     } catch (Throwable t) {    
  20.       // we should never get here    
  21.       Util.reportFailure("Failed to instantiate ["    
  22.           + LoggerContext.class.getName() + "]", t);    
  23.     }    
  24.   }    


獲取配置信息初始化

[java] view plain copy
  1. autoConfig ….    
  2. public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {    
  3.     ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);    
  4.     URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);    
  5.     if (url != null) {    
  6.       return url;    
  7.     }    
  8.     
  9.     url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader);    
  10.     if (updateStatus) {    
  11.       statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url);    
  12.     }    
  13.     if (url != null) {    
  14.       return url;    
  15.     }    
  16.     
  17.     url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader);    
  18.     if (updateStatus) {    
  19.       statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url);    
  20.     }    
  21.     return url;    
  22.   }    
  23.     
  24.   public void autoConfig() throws JoranException {    
  25.     StatusListenerConfigHelper.installIfAsked(loggerContext);    
  26.     URL url = findURLOfDefaultConfigurationFile(true);    
  27.     if (url != null) {    
  28.       configureByResource(url);    
  29.     } else {    
  30.       BasicConfigurator.configure(loggerContext);    
  31.     }    
  32.   }    


最后畫張流程圖總結下,^_^

 

 


 

 

 

 

 

總結: log框架應該很好的詮釋了 facade , adapter , 實現上還是比較簡單的,很好的做到了接口和實現的分離,對今后的代碼組織有一定的啟發

 

轉載自 : http://myclqr.iteye.com/blog/1775541

------------------------------------------------------------------------------------

用slf4j+logback替代commons-logging+log4j
加載以下jar包:
slf4j-api.jar
logback-core.jar
logback-classic.jar
log4j-over-slf4j.jar
jcl104-over-slf4j.jar
同時刪除commons-logging.jar和log4j.jar
http://logback.qos.ch/translator/Welcome.do轉換log4j.properties為logback.xml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM