天天看点

MyBatis日志实现一-Java日志体系

作者:小雨在进步

在介绍MyBatis日志实现之前,我们有必要了解一下Java的日志体系以及日志框架的发展。目前比较常用的日志框架有以下几个。

Log4j:Apache Log4j是一个基于Java的日志记录工具。它是由Ceki Gülcü首创的,现在则是Apache软件基金会的一个项目。

Log4j 2:Apache Log4j 2是Apache开发的一款Log4j的升级产品。

Commons Logging:Apache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。

SLF4J:全称为Simple Logging Facade for Java,类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。

Logback:是一套日志组件的实现,属于SLF4J阵营。JUL:全称是Java Util Logging,是JDK1.4以后提供的日志实现。

可以想象一下,我们的项目中通常会依赖很多第三方工具包或者框架,如果这些工具包或框架使用不同的日志实现,那么我们的项目就要为每种不同的日志框架维护一套单独的配置,这会造成项目日志输出模块相当混乱。然而在实际项目中,我们只维护了一套日志配置,这些日志直接是怎样解决冲突的呢?

为了解决这个疑问,我们首先来了解一下Java日志的发展史。

1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到Java的标准库中,但被Sun拒绝了。

2002年,Java 1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),它的实现基本模仿了Log4j的实现。在JUL问世以前,Log4j就已经成为一项成熟的技术,这使得Log4j在选择上占据了一定的优势。

接着,Apache推出了JCL(Jakarta Commons Logging),它只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现。也就是说,在应用程序代码中,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是JUL。

后来(2006年),Log4j的作者不适应Apache的工作方式,离开了Apache。然后先后创建了SLF4J和Logback两个项目并回瑞典创建了QOS公司。SLF4J类似于Commons Logging,属于日志门面,而Logback是对SLF4J日志门面的实现,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用、可靠、快速且灵活的日志框架)。

现今,Java日志领域被划分为两大阵营:Commons Logging阵营和SLF4J阵营。Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底,有人分析了GitHub上的30000个项目,统计出了流行的100个Libraries,从图中可以看出SLF4J的发展趋势更好。

Apache眼看有被Logback反超的势头,于2012年重写了Log4j 1.x,成立了新的项目Log4j 2。Log4j 2具有logback的所有特性。

MyBatis日志实现一-Java日志体系

总结一下,这些日志框架之间的关系如图所示。JCL和SLF4J属于日志接口,提供统一的日志操作规范,输入日志功能由具体的日志实现框架(例如Log4j、Logback等)完成。

MyBatis日志实现一-Java日志体系

日志接口需要与具体的日志框架进行绑定,如果项目中使用JCL作为日志接口,则需要在Classpath下新增一个commons-logging.properties文件,通过该文件指定日志工厂的具体实现,例如:

MyBatis日志实现一-Java日志体系

如果需要修改具体的日志实现,则只需要修改org.apache.commons.logging.Log属性值,应用代码无须做任何调整。

SLF4J的设计相对较为精巧,将接口和实现分开。其中,SLF4J-api中定义了日志接口。开发者需要关心的就是这个接口,无须关心下层如何实现,同时各个SLF4J接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容。

有接口就要有实现,比较推崇的实现是Logback框架,Logback完全实现了SLF4J-api的接口,并且性能比Log4j更好,同时实现了变参占位符日志输出方式等新特性。但是Log4j框架的使用仍然比较普遍,所以支持这批用户是必需的。SLF4J-log4j12也实现了SLF4J-api,这个是对Log4j的适配器。同样推理,也有对JUL的适配器SLF4J-jdk14等。为了让使用JCL等其他日志系统的用户可以很简单地切换到SLF4J上来,这些日志框架给出了各种桥接工程,比如jcl-over-SLF4J把对JCL的调用都桥接到SLF4J上,可以看出jcl-over-SLF4J的API和JCL是相同的,所以这两个JAR包是不能共存的。jul-to-SLF4J是把对JUL的调用桥接到SLF4J上,log4j-over-SLF4J是把对Log4j的调用桥接到SLF4J。

这些模块之间的关系如图所示,最上层表示桥阶层,用于使其他日志框架的调用转接到SLF4J-api。最下层表示具体的实现层,即针对其他日志框架实现的适配器,这些适配器都实现了SLF4J-api中定义的日志操作规范。中间是SLF4J-api接口,可以看出图中所有的JAR都是围绕着SLF4J-api活动的。

MyBatis日志实现一-Java日志体系

使用SLF4J绑定其他日志框架需要的JAR包如图所示。例如,在应用程序中,如果使用SLF4J接口编写日志输出代码,底层的日志框架为Log4j,则需要在项目中同时引入SLF4J-api.jar、SLF4J-log412.jar和log4j.jar。当我们需要将日志输出框架换成Logback时,只需要将SLF4J-log412.jar、log4j.jar替换成bagback-classic.jar和logback-core.jar即可,应用程序代码无须做任何调整。

MyBatis日志实现一-Java日志体系