今天看到了一篇对Java日志系统讲解很不错的文章,所以做个学习记录,如有侵权请联系删除
概述
Java的日志系统非常丰富,常用的有log4j、JUL、logback等等,随着日志系统的发展出现了日志框架commons-logging、slf4j
发展史
日志最早出现的是apache开源社区的log4j,是应用最为广泛的日志工具,然而sun公司在JDK1.4中增加了JUL日志实现企图对抗log4j,同时断断续续也出现了其他的日志工具,这就造成了混乱,因为这些日志系统互相没有关联,替换和统一变得棘手,想象一下你的应用使用了log4j,然后使用了其他团队的库,而他们使用了JUL,那么你的应用就需要使用两个日志系统了,然后又有第二个库使用了simplelog,这个时候估计你就会崩溃了…那么如何解决呢?进行抽象,抽象出一个接口层对每个日志实现都适配或者转接,提供给别人的库都直接使用抽象层而具体的实现由使用者决定。不错,开源社区提供了commons-logging抽象,被称为JCL,JCL确实出色的完成了兼容主流的日志实现(log4j、JUL、simplelog),基本一统江湖,就连大名鼎鼎的spring也是依赖了JCL。然而好景不长,另一个优秀的日志框架slf4j的出现使场面更加混乱,而slf4j的作者(Ceki Gülcü)正是log4j的作者,他觉得JCL不够优秀所以要搞一套更优雅的出来,于是slf4j诞生了,同时为slf4j实现了一个亲儿子——logback。
slf4j确实更加优雅,但是之前已有很多代码库已经使用了JCL,虽然出现了slf4j与JCL之间的桥接转换,但是集成的时候依然问题多多,到此本来应该完了,但是Ceki Gülcü觉得还是得回头拯救下自己的“大阿哥”——log4j,于是log4j2诞生了,同样log4j2也参与到了slf4j日志体系中,想必将来会更加混乱…
JCL
使用JCL一般需要配置一个commons-logging.properties在classpath上,这个文件有一行代码:
org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl
这个是告诉JCL我们要使用哪个日志实现,JCL会在classpath下去加载对应的日志工厂实现类,具体的日志工厂实现类可以是log4j,也可以是jul等等。用户主需要依赖JCL的api即可,对日志系统的替换主需要修改一下commons-logging.properties文件切换到对应的日志工厂实现即可,但是我们也可以看到因为JCL是在运行时去加载classpath下的实现类,会有classloader的问题。
slf4j
slf4j的设计确实比较优雅,它采用了我们比较熟悉的方式——接口和实现分离,有个纯粹的接口层slf4j-api工程,这个里面基本完全定义了日志的接口,所以对于开发者来说只需要是这个即可。
有接口就要有实现,比较推崇的实现是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,下面用一张图来表示下这个家族的大致成员(红线表示冲突)
如上图所示,最上层表示桥接层,中间是接口层,最下层表示具体的实现,可以看出这个图中所有的jar都是围绕着slf4j活动的,其中slf4j-jul的jar包名称是slf4j-jdk14