遇到了同樣的問題,
我的解決辦法是在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代碼
- package com.taobao.wuzhong.log;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.junit.Test;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * DESC:
- *
- * Copyright: Copyright 2011 m.taobao.com
- *
- * @author wuzhong@taobao.com
- * @time 2011-4-6 下午03:42:11
- * @version 1.0
- **/
- public class LogTest {
- // Logback tries to find a file called logback.groovy in the classpath.
- // If no such file is found, logback tries to find a file called
- // logback-test.xml in the classpath.
- // If no such file is found, it checks for the file logback.xml in the
- // classpath..
- // If neither file is found, logback configures itself automatically using
- // the BasicConfigurator which will cause logging output to be directed to
- // the console.
- @Test
- public void test() {
- //commons-logging的方式獲取
- Log log = LogFactory.getLog(LogTest.class);
- //slf4j直接的方式獲取,推薦用這個
- Logger log2 = LoggerFactory.getLogger(LogTest.class);
- log.debug("eeeeee {} {} {}");
- log2.debug("{} {} {}", new String[] { "a", "b", "c" });
- }
- }
logFactory.getLog 會調用內部靜態變量 Slf4jLogFactory.getInstance方法,如下:
public Log getInstance(String name) throws LogConfigurationException {
- Log instance = null;
- // protect against concurrent access of loggerMap
- synchronized (this) {
- instance = (Log) loggerMap.get(name);
- if (instance == null) {
- Logger logger = LoggerFactory.getLogger(name); //slf4j的方式,代理過去了
- if(logger instanceof LocationAwareLogger) {
- instance = new SLF4JLocationAwareLog((LocationAwareLogger) logger); //包裝了一層,做適配
- } else {
- instance = new SLF4JLog(logger);
- }
- loggerMap.put(name, instance);
- }
- }
- return (instance);
loggerFactory 會調用getILoggerFactory().getlOgger()
- LoggerFactory.java
- public static ILoggerFactory getILoggerFactory() {
- if (INITIALIZATION_STATE == UNINITIALIZED) {
- INITIALIZATION_STATE = ONGOING_INITILIZATION;
- performInitialization();
- }
- switch (INITIALIZATION_STATE) {
- case SUCCESSFUL_INITILIZATION:
- return getSingleton().getLoggerFactory();
- case FAILED_INITILIZATION:
- throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
- case ONGOING_INITILIZATION:
- // support re-entrant behavior.
- // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
- return TEMP_FACTORY;
- }
- throw new IllegalStateException("Unreachable code");
- }
- private final static void performInitialization() {
- bind();
- versionSanityCheck();
- singleImplementationSanityCheck();
- }
這里的bind很關鍵,這里動態的綁定了slf4j-api的實現機制
- static {
- SINGLETON.init();
- }
- /**
- * Package access for testing purposes.
- */
- void init() {
- try {
- try {
- new ContextInitializer(defaultLoggerContext).autoConfig();
- } catch (JoranException je) {
- Util.reportFailure("Failed to auto configure default logger context",
- je);
- }
- StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
- contextSelectorBinder.init(defaultLoggerContext, KEY);
- initialized = true;
- } catch (Throwable t) {
- // we should never get here
- Util.reportFailure("Failed to instantiate ["
- + LoggerContext.class.getName() + "]", t);
- }
- }
獲取配置信息初始化
- autoConfig ….
- public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
- ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
- URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
- if (url != null) {
- return url;
- }
- url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url);
- }
- if (url != null) {
- return url;
- }
- url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader);
- if (updateStatus) {
- statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url);
- }
- return url;
- }
- public void autoConfig() throws JoranException {
- StatusListenerConfigHelper.installIfAsked(loggerContext);
- URL url = findURLOfDefaultConfigurationFile(true);
- if (url != null) {
- configureByResource(url);
- } else {
- BasicConfigurator.configure(loggerContext);
- }
- }
最后畫張流程圖總結下,^_^

總結: 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
