`
macken
  • 浏览: 341894 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

slf4j源码分析

    博客分类:
  • Java
 
阅读更多

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2
1
分享到:
评论
2 楼 kyfxbl 2012-12-11  
slf4j只是一个facade,值得研究的点不多。真要研究日志框架的源码,可以看一下logback和commons-logging
1 楼 wxl24life 2012-12-11  
感谢。最近也在看源码,正在琢磨用什么方式记录源码分析的过程。

引用
一点小建议
StaticBinderLogger定义(只提取了部分代码)


既然提取部分代码,至少关键的细节不要漏掉
建议补全 getSingleton() 方法的实现

相关推荐

    slf4j使用和源码分析

    slf4j使用 SLF4J 是为各种 loging APIs 提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的 loging APIs 实现。 Logging API 实现既可以选择直接实现 SLF4J 接的 loging APIs 如: NLOG4J、...

    zookeeper源码阅读

    ZooKeeper的类初始化 ZooKeeper在初始化的时候, 会调用类初始化方法, 初始化日志环境(使用SLF4J), 并且记录相关环境变量. 环境变量被存放在Environment的类中, 使用System.getProperty获得相应的环境变量, 内部使用...

    java秒杀项目源码-seckill:Java高并发秒杀项目

    org.slf4j slf4j-api 1.7.21 ch.qos.logback logback-core 1.1.1 ch.qos.logback logback-classic 1.1.1 mysql mysql-connector-java 5.1.35 c3p0 c3p0 0.9.1.2 org.mybatis mybatis 3.3.0 org.mybatis myba

    java版ss源码-ErRabbit:使用Log4j的远程日志控制台服务器。可视化异常堆栈跟踪日志视图

    Log4j、slf4j(by Plinio Freire) 和 ActiveMQ 收集将使其与其他程序轻松兼容。 介绍幻灯片 有什么区别。 RrRabbit 旨在可视化错误日志 易于集成到现有的 Java 应用程序上。 한국어 설명은 에 있습니다。 结构 Web ...

    SpringBoot就业管理系统源码.zip

    本系统为就业管理系统,主要围绕高校毕业生的毕业情况进行跟踪和分析,为学校领导对专业设置优化,为高校毕业生就业方向提供参考。...日志:SLF4J 1.7、Log4j 前端框架:Layui,ztree,jquery,echarts

    JAVA上百实例源码以及开源项目源代码

    Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...

    JAVA上百实例源码以及开源项目

    笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...

    java开源包8

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    t淘淘商城项目 商城项目 视频和源码教程 详细

    &lt;slf4j.version&gt;1.6.4&lt;/slf4j.version&gt; &lt;jackson.version&gt;2.4.2 &lt;druid.version&gt;1.0.9 &lt;httpclient.version&gt;4.3.5 &lt;jstl.version&gt;1.2 &lt;servlet-api.version&gt;2.5 &lt;jsp-api.version&gt;2.0 &lt;joda-time.version&gt;2.5...

    java开源包4

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    大数据培训课程安排.pdf

    主要技术包括:Hibernate、Spring、SpringMVC、log4j slf4j 整合、myBatis、struts2、Shiro 、redis、流程引擎activity, 爬 ⾍技术nutch,lucene,webService CXF、Tomcat集群和热备 、MySQL读写分离 4. 描述如下:...

    java开源包1

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包11

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包2

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包3

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包6

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包5

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包10

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

    java开源包7

    BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。 异步输出框架 AsynWriter 一个Java的类库,用于异步输出记录的简单小框架用于高并发下数据输出使用...

Global site tag (gtag.js) - Google Analytics