几乎任何应用,一定是需要日志的。

  那么,面对种类繁多的日志框架和配置,我们该何去何从?

  1.前奏:我是在研究mybatis源码的过程中才意识到需要搞明白日志原理这回事,因为mybatis(和一些其他开源框架,比如rocketmq)都有自己的日志系统,他们在框架内部都使用的是自己的日志API,那么,为什么他们不像我们平常那样配置一个log4j呢?根本原因我也不太清楚,不过我猜测可能有这么一些理由,这些框架比较老,当初还没有slf4j这种事实上的标准,另一方面,有一些特殊的定制化的日志。彻底研究清楚mybatis的日志系统之后,个人觉得这一块设计得不太好,至少今天看来,不太优雅,因为本来一个slf4j就能搞定所有,非得在源码中加入自己的org.apache.ibatis.logging这个包,里面包含一些适配器,虽然代码并不复杂,但是有点多此一举。

  2.原理:slf4j是标准,也是门面,他对用户提供统一的API,而下方对接各个日志框架。这有点类似JVM,我们Java开发者使用统一的API,而JVM对接各个操作系统。严格意义上说slf4j自身并不提供日志具体实现。图片来自:https://www.cnblogs.com/hanszhao/p/9754419.html

  3.slf4j采用的是SPI机制,指定一个标准的目录结构:org.slf4j.impl.StaticLoggerBinder,然第三方的框架都必须存在一个这样的类,用于和slf4j建立关系,比如slf4j-simple.jar,logback,这两个直接实现了slf4j的接口,而对于log4j这种则需要一个中间适配器slf4j-log4j12。于是乎,当调用slf4j的Logger logger = LoggerFactory.getLogger(XXX.class)的时候,虽然使用的是slf4j的api,但是真正输出日志的是具体的日志框架,这样子做的好处就是,当某一天你希望更换日志框架了,只需要把具体日志框架的jar包替换掉,不需要更改任何一行代码,就能实现日志框架的切换。

  4.slf4j是如何发现具体日志框架的,这就得意于spi机制,前面说每个日志框架都需要存在一个org.slf4j.impl.StaticLoggerBinder类,log4j则是通过中间适配器slf4j-log4j12。当调用LoggerFactory.getLogger的时候,就会去classpath中寻找StaticLoggerBinder这个类,如果不存在或者存在超过1个,那么会报错,classpath有且只能存在一个StaticLoggerBinder类。

  5.分析mybatis的日志框架:mybatis有一套属于自己的日志系统,采用适配器模式,自己并不实现具体日志库框架,而是整合第三方日志框架。日志api是:Log log = LogFactory.getLog(xxx.class),于此同时,封装了几个主流的日志框架适配器,包括:SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING,当调用Log log = LogFactory.getLog(xxx.class)时,会初始化众多适配器中的一个,可以在mybatis的配置文件中通过logImpl指定具体的一个,如果不指定那么默认使用SLF4J,因为这里在LogFactory类中的静态代码快第一个就是SLF4J:

  static {
tryImplementation(LogFactory::useSlf4jLogging);
tryImplementation(LogFactory::useCommonsLogging);
tryImplementation(LogFactory::useLog4J2Logging);
tryImplementation(LogFactory::useLog4JLogging);
tryImplementation(LogFactory::useJdkLogging);
tryImplementation(LogFactory::useNoLogging);
}

假设使用默认配置,那么就会初始化Slf4jImpl类,这个类内部有个代理log,这个代理log就是Logger logger = LoggerFactory.getLogger(clazz),这就回归到slf4j的标准使用方式上面来了,mybatis打印日志,其实就是代理对象在打印,而代理对象就是classpath中配置的具体日志框架。

  6.分析log4j是如何与slf4j整合的:前面说到,要使用log4j就必须引入slf4j-log4j12这个jar包,而这个jar包中同样存在一个StaticLoggerBinder类,当我们调用LoggerFactory.getLogger(clazz)的时候,同样是初始化StaticLoggerBinder,然后调用利用ILoggerFactory创建一个log4j的Logger实例,代码如下:

 public class Log4jLoggerFactory implements ILoggerFactory {

   // key: name (String), value: a Log4jLoggerAdapter;
ConcurrentMap<String, Logger> loggerMap; public Log4jLoggerFactory() {
loggerMap = new ConcurrentHashMap<String, Logger>();
} /*
* (non-Javadoc)
*
* @see org.slf4j.ILoggerFactory#getLogger(java.lang.String)
*/
public Logger getLogger(String name) {
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
org.apache.log4j.Logger log4jLogger;
if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
log4jLogger = LogManager.getLogger(name); Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
}

最关键的一行就是第27行Logger newInstance = new Log4jLoggerAdapter(log4jLogger),slf4j的Logger对象实际上是一个log4j的适配器对象(也是代理对象),当slf4j调用比如debug方法的时候,实际上是代理对象(也就是真实的log4j对象)在调用debug方法。

Java日志之Slf4j,Log4J,logback原理总结的更多相关文章

  1. Java日志:集成slf4j和logback

    Java日志方案有很多,包括:java.util.logging.Apache的commons-logging和log4j.slf4j以及logback. 一个大型项目会用到众多第三方jar包,这些j ...

  2. Java日志框架Slf4j+Log4j入门

    一.日志系统介绍 slf4j,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统.简答的讲就是slf4j是一系列的日志 ...

  3. java日志之slf4j与logback简单使用

    最近在开发遇到日志是使用slf4j与logback.xml的配置,所以就记录下来了. 1.导入这几个jar包: Logback 分为三个模块:logback-core,logback-classic, ...

  4. slf4j log4j logback关系详解和相关用法

    slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着"拿来主义"的态度,复制粘贴下配 ...

  5. slf4j,log4j,logback 初步使用

    log4j,slf4j,logback简单介绍见 LogBack简易教程 Logback浅析 简单的将,slf4j是一个日志的框架,有各种日志的接口,但是并不包含实际的写日志的方法. log4j,lo ...

  6. slf4j log4j logback log4j2关系详解和相关用法

    来源:slf4j log4j logback关系详解和相关用法https://www.cnblogs.com/Sinte-Beuve/p/5758971.html The Simple Logging ...

  7. java 日志技术汇总(log4j , Commons-logging,.....)

    前言 在Tomcat 与weblogic 中的 日志(log4j) 配置系列一 在系列一 中, 有一个问题一直没有解决,就是部署到weblogic 中应用程序如何通过log4j写日志到文件中? 这里仅 ...

  8. Java日志框架SLF4J和log4j以及logback的联系和区别

    1.SLF4J(Simple logging Facade for Java) 意思为简单日志门面,它是把不同的日志系统的实现进行了具体的抽象化,只提供了统一的日志使用接口,使用时只需要按照其提供的接 ...

  9. Java日志框架 (commons-logging,log4j,slf4j,logback)

    转自:http://blog.csdn.net/kobejayandy/article/details/17335407 如果对于commons-loging.log4j.slf4j.LogBack等 ...

随机推荐

  1. Tomcat源码分析 (一)----- 手写一个web服务器

    作为后端开发人员,在实际的工作中我们会非常高频地使用到web服务器.而tomcat作为web服务器领域中举足轻重的一个web框架,又是不能不学习和了解的. tomcat其实是一个web框架,那么其内部 ...

  2. Postgresql部署及简单操作

    PostgreSQL是一个功能强大的开源对象关系数据库管理系统(ORDBMS),在开源数据库使用上与MySQL各领风骚.但也有不少人质疑postgresql的未来,正所谓,赞扬或批判一种数据库都必须先 ...

  3. python3学习-pickle模块

    pickle提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上. 基本接口: pickle.dump(obj, file, [,protocol]) 注解:将对象obj保存到文件file中 ...

  4. [转载]使用Java操作Mongodb

    HelloWorld程序 学习任何程序的第一步,都是编写HelloWorld程序,我们也不例外,看下如何通过Java编写一个HelloWorld的程序. 首先,要通过Java操作Mongodb,必须先 ...

  5. tensorflow学习笔记——图像识别与卷积神经网络

    无论是之前学习的MNIST数据集还是Cifar数据集,相比真实环境下的图像识别问题,有两个最大的问题,一是现实生活中的图片分辨率要远高于32*32,而且图像的分辨率也不会是固定的.二是现实生活中的物体 ...

  6. CodeForces 939F Cutlet

    洛谷题目页面传送门 & CodeForces题目页面传送门 题意见洛谷里的翻译. 这是一道毒瘤的div. 2 F,我是不可能比赛的时候做出来的... (以下设两面都要煎\(n\)分钟,有\(m ...

  7. 003——Netty之Buffer、Channel以及多路复用器Selector

    Buffer 1.缓冲区类型 2.缓冲区定义 (1)Buffer是一个对象,其中包含写入与读出的数据.是新IO与原IO的重要区别.任何情况下访问NIO中的数据都需要通过缓存区进行操作. (2)Buff ...

  8. 记基于docker+gunicorn部署sanic项目遇到的很多很多坑

    前言: 最近有个项目需要上线,是python中sanic网络异步框架写的,并且要求使用docker+nginx来部署项目实现负载均衡,于是乎百度了sanic项目部署,基本上都是基于docker+gun ...

  9. iOS 11 变化

    首先我是开发者,更关心对技术的影响,我又需要关注.学习哪些技术,猫神的文章:http://www.cocoachina.com/ios/20170607/19457.html 介绍了 ******** ...

  10. 2018年蓝桥杯b组国赛真题

    1.标题:换零钞x星球的钞票的面额只有:100元,5元,2元,1元,共4种.小明去x星旅游,他手里只有2张100元的x星币,太不方便,恰好路过x星银行就去换零钱.小明有点强迫症,他坚持要求200元换出 ...