代码改变世界

log4j源码学习---加载Logger

2012-08-28 16:05  Polarisary  阅读(1696)  评论(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的实现类呢?

StaticLoggerBinder
 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&uuml;lc&uuml;
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……