log4j源码学习---加载Logger
2012-08-28 16:05 Polarisary 阅读(1697) 评论(1) 编辑 收藏 举报时间过得真快,毕业2个月了,一直没有时间静下心来学些新技术,每天煎药,喝药,很痛苦又占用了大量的时间。
前几天在博客园申请了个博客,准备写些东西已记录工作过程中的一些心得。
最近工作上不忙,开始时学习dubbo和zookeeper及thrift,了解了其应用场景及方法,就想读下dubbo的源码,都是dubbo写得相当好,但刚开始就得结束了,因为
dubbo确实是个不小的框架,并且又刚开始学应用,又没有阅读源码的经验,所以现在读dubbo源码非常的吃力,所以就想从较小且常用的log4j开始试着读源码,
才有了这个系列的一些心得体会,记录下来,权当笔记了。
1.slf4j和log4j
首先,slf4j算是日志系统的门面,他并没有提供记录日志的实现,我们使用他可以在开发过程中方便的切换日志系统,如:log4j,logBack,jcl等
2.分析
slf4j中三个文件比较重要,两个接口:Logger;ILoggerFactory,和一个final类LoggerFactory
每个日志框架都需要实现Logger和ILoggerFactory接口,我们在使用的时候通常是 Logger logger = LoggerFactory.getLogger(XXX.class);
很明显LoggerFactory是框架的入口。下面看下LoggerFactory是怎样提供日志类的?
1 /** 2 * Return a logger named according to the name parameter using the statically 3 * bound {@link ILoggerFactory} instance. 4 * 5 * @param name 6 * The name of the logger. 7 * @return logger 8 */ 9 public static Logger getLogger(String name) { 10 ILoggerFactory iLoggerFactory = getILoggerFactory(); 11 return iLoggerFactory.getLogger(name); 12 }
通过私有的 getILoggerFactory()得到ILoggerFactory 实现类的实例,通过这个实例根据名称得到Logger
1 /** 2 * Return the {@link ILoggerFactory} instance in use. 3 * 4 * <p> 5 * ILoggerFactory instance is bound with this class at compile time. 6 * 7 * @return the ILoggerFactory instance in use 8 */ 9 public static ILoggerFactory getILoggerFactory() { 10 if (INITIALIZATION_STATE == UNINITIALIZED) { 11 INITIALIZATION_STATE = ONGOING_INITILIZATION; 12 performInitialization(); 13 14 } 15 switch (INITIALIZATION_STATE) { 16 case SUCCESSFUL_INITILIZATION: 17 return StaticLoggerBinder.getSingleton().getLoggerFactory(); 18 case NOP_FALLBACK_INITILIZATION: 19 return NOP_FALLBACK_FACTORY; 20 case FAILED_INITILIZATION: 21 throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); 22 case ONGOING_INITILIZATION: 23 // support re-entrant behavior. 24 // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 25 return TEMP_FACTORY; 26 } 27 throw new IllegalStateException("Unreachable code"); 28 }
这个方法是重点了,他决定了要调用哪个日志框架。为了得到ILoggerFactory的实现类,先判断初始化是否成功,没有成功则委托给NOPLoggerFactory提供Logger,
其实他是一个空的实现,什么也不做。初始化成功则通过StaticLoggerBinder委托给具体的日志实现框架。
那么这个StaticLoggerBinder类有谁提供呢?
既然要灵活的绑定日志实现框架,他肯定不能在slf4j中写死了,在具体的日志实现框架中定义又不能跟slf4j联系。所以这个类既不属于slf4j又不属于具体的实现
框架,我们在导jar包的时候通常是导入三个jar包:
Maven: org.slf4j:slf4j-api:1.6.1
Maven: org.slf4j:slf4j-log4j12:1.6.1
Maven: log4j:log4j:1.2.16
这是log4j的,其中Maven: org.slf4j:slf4j-log4j12:1.6.1是在中间其承上启下的作用的,如果要使用logback的话就要换slf4j-logback****及logback.jar了。
上面有个方法忘了,初始化时调用performInitialization(),用来判断类路径的日志实现jar,这里只能有一个,也就是说要么用log4j,要么用logback或jcl。
再者StaticLoggerBinder是怎么提供ILoggerFactory的实现类呢?
1 package org.slf4j.impl; 2 3 import org.apache.log4j.Level; 4 import org.slf4j.ILoggerFactory; 5 import org.slf4j.LoggerFactory; 6 import org.slf4j.helpers.Util; 7 import org.slf4j.spi.LoggerFactoryBinder; 8 9 /** 10 * The binding of {@link LoggerFactory} class with an actual instance of 11 * {@link ILoggerFactory} is performed using information returned by this class. 12 * 13 * @author Ceki Gülcü 14 */ 15 public class StaticLoggerBinder implements LoggerFactoryBinder { 16 17 /** 18 * The unique instance of this class. 19 * 20 */ 21 private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); 22 23 /** 24 * Return the singleton of this class. 25 * 26 * @return the StaticLoggerBinder singleton 27 */ 28 public static final StaticLoggerBinder getSingleton() { 29 return SINGLETON; 30 } 31 32 /** 33 * Declare the version of the SLF4J API this implementation is compiled 34 * against. The value of this field is usually modified with each release. 35 */ 36 // to avoid constant folding by the compiler, this field must *not* be final 37 public static String REQUESTED_API_VERSION = "1.6"; // !final 38 39 private static final String loggerFactoryClassStr = Log4jLoggerFactory.class 40 .getName(); 41 42 /** 43 * The ILoggerFactory instance returned by the {@link #getLoggerFactory} 44 * method should always be the same object 45 */ 46 private final ILoggerFactory loggerFactory; 47 48 private StaticLoggerBinder() { 49 loggerFactory = new Log4jLoggerFactory(); 50 try { 51 Level level = Level.TRACE; 52 } catch (NoSuchFieldError nsfe) { 53 Util 54 .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version"); 55 } 56 } 57 58 public ILoggerFactory getLoggerFactory() { 59 return loggerFactory; 60 } 61 62 public String getLoggerFactoryClassStr() { 63 return loggerFactoryClassStr; 64 } 65 }
由代码容易看出,他使用一个简单单例类,返回的则是具体日志框架的LoggerFactory实现,这里是Log4jLoggerFactory,这样的话前面getLogger()方法得到Logger对象肯定是具体日志框架的Logger。
End……