近期由于想利用应用程序的输出日志做一些应用,了解了下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包