slf4j源码分析

近期由于想利用应用程序的输出日志做一些应用,了解了下java的log框架,先说slf4j,slf4j用来做什么的呢?官网解释

     

     The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time

slf4j为不同的日志框架提供统一的日志接口,在编译时即将绑定了相应的日志框架(静态绑定)。slf4j的好处自行百度。

 

slf4j的源码结构分为三部分

1.原有日志接口到slf4j的桥接包 如jcl-over-slf4j,jul-to-slf4j;

2.slf4j到各个日志框架桥接包,如slf4j-log12,slf4j-jdk14;

3.slf4j-api 核心api包,对外提供统一接口;

 

主要分析slf4j-api的实现,后续以slf4j+log4j、slf4j+logback举例说明

 

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestLog {
	public static final Logger logger=LoggerFactory.getLogger(TestLog.class);
	public static void main(String[] args) {
		logger.info("{}","macken");
	}
}

 

 常用使用方式,如上代码所示

slf4j-api提供了Logger(接口)、LoggerFacotry(类)

LoggerFactory的getLogger方法

 

public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
  }

 

 调用getILoggerFactory获得一个实现了ILoggerFactory接口的对象,查看getILoggerFactory方法

 

public static ILoggerFactory getILoggerFactory() {
    if (INITIALIZATION_STATE == UNINITIALIZED) {
      INITIALIZATION_STATE = ONGOING_INITIALIZATION;
      performInitialization();
    }
    switch (INITIALIZATION_STATE) {
      case SUCCESSFUL_INITIALIZATION:
        return StaticLoggerBinder.getSingleton().getLoggerFactory();
      case NOP_FALLBACK_INITIALIZATION:
        return NOP_FALLBACK_FACTORY;
      case FAILED_INITIALIZATION:
        throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
      case ONGOING_INITIALIZATION:
        // support re-entrant behavior.
        // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
        return TEMP_FACTORY;
    }
    throw new IllegalStateException("Unreachable code");
  }

 switch前的一通检查,检查是否存在StaticLoggerBinder类,是否存在几个,如果状态是SUCCESSFUL_INITIALIZATION,则调用StaticLoggerBinder.getSingleton().getLoggerFactory()

通过这个方法实现静态绑定,StaticLoggerBinder的实现不同的日志框架实现不同,返回的LoggerFacotry必须实现了ILoggerFactory接口;

 

以log4j的桥接包slf4j-log4j12的实现为例

 

其中Log4jLoggerFactory定义

 

public class Log4jLoggerFactory implements ILoggerFactory {

  // key: name (String), value: a Log4jLoggerAdapter;
  Map loggerMap;
}

 

 StaticBinderLogger定义(只提取了部分代码)

 

 

public class StaticLoggerBinder implements LoggerFactoryBinder {

	private final ILoggerFactory loggerFactory;

	private StaticLoggerBinder() {
		loggerFactory = new Log4jLoggerFactory();
		try {
			Level level = Level.TRACE;
		} catch (NoSuchFieldError nsfe) {
			Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
		}
	}

	public ILoggerFactory getLoggerFactory() {
		return loggerFactory;
	}

}

 

 

StaticBinderLogger、Log4jLoggerFactory都是单例模式,StaticBinderLogger获取一个Log4jLoggerFactory,它实现了ILoggerFactory接口,Log4jLoggerFactory维护一个loggerMap,保证同名的logger只创建一次,根据传入的logger名返回对应的Logger,由于Log4j的Logger对象与slf4j的Logger接口不完全相同,需要在Log4j的Logger对象上进行一层封装,因此使用了Log4jLoggerAdapter,getLogger代码

 

public Logger getLogger(String name) {
    Logger slf4jLogger = null;
    // protect against concurrent access of loggerMap
    synchronized (this) {
        slf4jLogger = (Logger) loggerMap.get(name);
      if (slf4jLogger == null) {
        org.apache.log4j.Logger log4jLogger;
        if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) {
           log4jLogger = LogManager.getRootLogger();
        } else {
          log4jLogger = LogManager.getLogger(name);
        }
        slf4jLogger = new Log4jLoggerAdapter(log4jLogger);
        loggerMap.put(name, slf4jLogger);
      }
    }
    return slf4jLogger;
  }

slf4j+log4j使用的pom配置

 

<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.14</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.1</version>
		</dependency>

 

 可能是由于slf4j的作者同时也是log4j的作者觉得slf4j与log4j搭档起来不是很和谐,或者log4j性能比较挫,就写了一个slf4j的完全实现logback,性能也提高了不少

值得一提的是Log4jLoggerFactory使用的是HashMap存储logger对象,而在logback中的factory类LoggerContext使用HashTable存储logger对象,所以使用slf4j+log4j使用时不时线程安全的。

logback的pom配置直接引入就可以,内置包含slf4j-api包

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(slf4j)