log日志框架的学习

 

Commons-log + log4j 这黄金搭档一直以来都让我们很省心,很好的完成了日志的需求。但是随着技术的变更和对性能的追求,slf4j 和 logback 这对后起之秀的到来好像打破了原本很平静的日志系统,频繁的出现包冲突... 

       和平的日子不在了,让我们一起来看看究竟发生了什么...

 

 

首先看看这些个包,特别是slf4j引入后就引入了一大堆包之后就有点懵了。


为什么commons-logging和jcl-over-slf4j会有冲突呢?看一下它们的类结构


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

 

还有slf4j-api的实现呢,同样看类:

其实就这么简单,往往看了代码之后才发现错误是这么显而易见。。。

 

 

顺着研究,继续看一下slf4j的源码及流程

1.测试类

 

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 , 实现上还是比较简单的,很好的做到了接口和实现的分离,对今后的代码组织有一定的启发

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值