log日志框架和LocationAwareLogger问题

来源:互联网 发布:开淘宝店需要什么费用 编辑:程序博客网 时间:2024/05/22 20:02

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

logFactory.getLog 会调用内部静态变量 Slf4jLogFactory.getInstance方法,如下:

public Log getInstance(String name) throws LogConfigurationException {

Java代码 复制代码 收藏代码
  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代码 复制代码 收藏代码
  1. LoggerFactory.java
  2. public static ILoggerFactory getILoggerFactory() {
  3. if (INITIALIZATION_STATE == UNINITIALIZED) {
  4. INITIALIZATION_STATE = ONGOING_INITILIZATION;
  5. performInitialization();
  6. }
  7. switch (INITIALIZATION_STATE) {
  8. case SUCCESSFUL_INITILIZATION:
  9. return getSingleton().getLoggerFactory();
  10. case FAILED_INITILIZATION:
  11. throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
  12. case ONGOING_INITILIZATION:
  13. // support re-entrant behavior.
  14. // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
  15. return TEMP_FACTORY;
  16. }
  17. throw new IllegalStateException("Unreachable code");
  18. }
  19. private final static void performInitialization() {
  20. bind();
  21. versionSanityCheck();
  22. singleImplementationSanityCheck();
  23. }

这里的bind很关键,这里动态的绑定了slf4j-api的实现机制

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

获取配置信息初始化

原创粉丝点击