`

Log日志框架的学习二.slf4j源代码分析

阅读更多

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

 

 

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.     }  
  8.     switch (INITIALIZATION_STATE) {  
  9.     case SUCCESSFUL_INITILIZATION:  
  10.       return getSingleton().getLoggerFactory();  
  11.     case FAILED_INITILIZATION:  
  12.       throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);  
  13.     case ONGOING_INITILIZATION:  
  14.       // support re-entrant behavior.  
  15.       // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106  
  16.       return TEMP_FACTORY;  
  17.     }  
  18.     throw new IllegalStateException("Unreachable code");  
  19.   }  
  20.   
  21.  private final static void performInitialization() {  
  22.     bind();  
  23.     versionSanityCheck();  
  24.     singleImplementationSanityCheck();  
  25.   
  26.   }  

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

 

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

 

获取配置信息初始化

 

Java代码  收藏代码
  1. autoConfig ….  
  2. public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {  
  3.     ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);  
  4.     URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);  
  5.     if (url != null) {  
  6.       return url;  
  7.     }  
  8.   
  9.     url = Loader.getResource(TEST_AUTOCONFIG_FILE, myClassLoader);  
  10.     if (updateStatus) {  
  11.       statusOnResourceSearch(TEST_AUTOCONFIG_FILE, myClassLoader, url);  
  12.     }  
  13.     if (url != null) {  
  14.       return url;  
  15.     }  
  16.   
  17.     url = Loader.getResource(AUTOCONFIG_FILE, myClassLoader);  
  18.     if (updateStatus) {  
  19.       statusOnResourceSearch(AUTOCONFIG_FILE, myClassLoader, url);  
  20.     }  
  21.     return url;  
  22.   }  
  23.   
  24.   public void autoConfig() throws JoranException {  
  25.     StatusListenerConfigHelper.installIfAsked(loggerContext);  
  26.     URL url = findURLOfDefaultConfigurationFile(true);  
  27.     if (url != null) {  
  28.       configureByResource(url);  
  29.     } else {  
  30.       BasicConfigurator.configure(loggerContext);  
  31.     }  
  32.   }  

 

最后画张流程图总结下,^_^


 

 

总结: log框架应该很好的诠释了 facade , adapter , 实现上还是比较简单的,很好的做到了接口和实现的分离,对今后的代码组织有一定的启发

分享到:
评论

相关推荐

    slf4j-log4j12 等jar包.rar

    5. **源码**:描述中提到的"源码"可能是指SLF4J和Log4j的源代码,这对于开发者理解内部工作原理,调试问题,甚至进行定制化开发非常有用。通过查看源代码,开发者可以学习到日志框架的设计思路,以及如何实现日志...

    slf4j日志框架的源代码分享

    SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。通过SLF4J,开发者可以在运行时绑定任意...

    slf4j-log4j12-1.5.0.jar 文件

    SLF4J(Simple Logging Facade for Java)与Log4j12的结合:slf4j-log4j12-1.5.0.jar SLF4J 是一个Java日志API的抽象层,它提供了一个简单的统一的接口,允许用户在运行时绑定具体的日志实现。SLF4J的主要目标是使...

    slf4j-1.6.1.tar.gz slf4j-1.6.1.zip slf4j-1.6.1

    SLF4J(Simple Logging Facade for Java)是Java日志框架的一个接口层,它为各种日志实现提供了一个统一的API,使得开发者能够在不修改代码的情况下切换不同的日志实现。这个“slf4j-1.6.1”版本是SLF4J的1.6.1稳定...

    MINA框架 多人聊天的技术原型 包含slf4j和Log4j配置

    SLF4J(Simple Logging Facade for Java)是一个日志抽象层,它为各种日志框架,如Log4j、java.util.logging、Logback等,提供了一个统一的接口。这样,开发者可以在不修改代码的情况下切换不同的日志实现,提高了...

    slf4j-1.5.6.tar.zip

    `slf4j-1.5.6.tar.gz`是一个进一步压缩的归档文件,通常包含SLF4J库的JAR文件、源代码、文档和其他资源。解压此文件后,用户可以获取到SLF4J的详细内容,包括API文档、示例代码和可能的绑定实现。而`Readme-说明....

    slf4j-all-log4j12-1.4.3.jar.zip CXF整合SSH你可能需要它

    SLF4J提供了一个抽象层,允许开发者选择自己喜欢的日志框架,如Logback、Log4j等。而Log4j则是Apache的一个经典日志组件,提供了丰富的日志记录功能。 在这个“slf4j-all-log4j12-1.4.3.jar.zip”压缩包中,包含的...

    slf4j-migrator-1.6.0.jar.zip

    SLF4J(Simple Logging Facade for Java)是一个用于各种日志框架的简单抽象,例如java.util.logging,Logback和Log4j。它的主要目的是为应用程序提供一个可以在部署时插拔的日志API,允许最终用户在部署时选择所需...

    slf4j-android-1.5.8.jar.zip

    SLF4J(Simple Logging Facade for Java)是Java中一个重要的日志抽象层,它为各种日志框架,如Logback、Log4j等,提供了一个统一的接口。SLF4J的主要目的是使得应用程序可以在部署时选择合适的日志实现,而无需在...

    slf4j-simple-1.7.25.rar

    SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供一个简单的统一接口,使得最终用户能够在部署时插入所需的日志实现。SLF4J的主要目标是允许最终用户在部署...

    slf4J的所有相关jar

    使用SLF4J的关键在于,通过在项目中引入`slf4j-api.jar`,然后根据实际需求选择合适的日志实现(如logback或log4j),并通过相应的适配器(如`slf4j-log4j12.jar`)桥接SLF4J接口与具体日志框架。这样,如果将来需要...

    slf4j-nop-1.5.8-sources.jar.zip

    SLF4J(Simple Logging Facade for Java)是Java中一个广泛应用的日志抽象层,它为各种日志框架,如Log4j、java.util.logging、Logback等提供了一个统一的接口。"slf4j-nop-1.5.8-sources.jar.zip" 文件是一个包含...

    slf4j-migrator.jar.zip

    4. **配置文件处理**:除了源代码,Migrator还可能处理与特定日志框架相关的配置文件,例如Log4j的log4j.properties或log4j.xml,将其转换为适合SLF4J的配置格式。 **SLF4J的主要优点:** 1. **灵活性**:SLF4J允许...

    slf4j-1.5.10.zip

    SLF4J的目的是简化日志库的使用,使开发人员能够在运行时绑定到任何兼容的日志框架,如Logback、Log4j或Java内置的日志系统。 `slf4j-1.5.10.zip`是一个包含SLF4J 1.5.10版本的压缩包。这个版本的SLF4J发布于某个...

    slf4j结合log4j的demo,带配置文件

    在提供的`slf4jDemo`中,可能包含了创建简单日志示例的Java源代码,以及相应的Log4j配置文件。通过运行这个示例,你可以直观地了解SLF4J和Log4j如何协同工作,以及如何配置和使用它们来满足项目的需求。通过实践,你...

    slf4j-1.7.2.zip

    SLF4J(Simple Logging Facade for Java)是Java中的一种日志门面(Logging Facade),它为各种日志框架提供了一个简单的统一接口,如Log4j、Java Util Logging、Logback等。这个"slf4j-1.7.2.zip"压缩包包含了SLF4J...

    slf4j.jdk14-1.6.1.jar

    SLF4J通过提供一组抽象的日志记录接口,使得开发者可以在不依赖具体日志实现的情况下编写代码,从而在不同的日志框架之间切换,如Log4j、Logback等。 SLF4J的"jdk14"模块是特别针对Java 1.4引入的,因为Java 1.4及...

    slf4j-1.5.11 jar包,源文件

    SLF4J(Simple Logging Facade for Java)是Java中的一种日志抽象层,它为各种日志框架,如Log4j、Logback等提供了一个简单的接口。SLF4J的主要目的是使应用程序能够在其开发阶段选择任何日志框架,而无需在部署时...

    slf4j-api-1.7.12.jar

    SLF4J(Simple Logging Facade for Java)是Java日志记录的一个接口层,它为各种日志框架,如Log4j、Java Util Logging、Logback等,提供了一个统一的API。`slf4j-api-1.7.12.jar`是SLF4J API的1.7.12版本的实现库,...

    slf4j-1.7.19

    SLF4J(Simple Logging Facade for Java)是Java日志框架的一个接口层,它为各种日志实现提供了一个统一的API,使得开发者能够在不修改代码的情况下切换不同的日志实现,如Log4j、Logback等。SLF4J的设计理念是通过...

Global site tag (gtag.js) - Google Analytics