相信大家在项目开发中肯定遇到过log4j
,JUL
,slf4j
,logback
,log4j2
等日志框架相关名词,这些日志框架之间到底有什么关系,Java日志框架究竟经历了什么样的发展历程,相信有很多人都对此充满了好奇。
下边将按照时间线对Java日志框架的发展历史进行介绍,从log4j
,JUL
,JCL
,到slf4j
,logback
,再到log4j2
。
Java日志框架为什么不断更新,层出不穷,它们之间又有什么关系,相信通过这篇文章你会对Java日志框架
有一个全新的认识!
博主主页:小新要变强的主页
Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)
首先来看一张Java日志生态图,其中蓝色部分是日志实现
,粉红色部分是日志门面
,白色部分是相关的绑定包
和桥接包
。(关于Java日志框架的详细介绍请期待我的下一篇文章)
初次看这张图肯定是比较懵逼的,各种包桥接过去桥接过来,绑定来绑定去,都是些啥玩意儿?
虽然看这张Java日志生态图很乱,很难梳理清楚,可能名字都不是很好记,但是如果我们从Java日志系统本身的发展历史去了解一下,可能就会明白为什么会出现图中这种情况了!
Java日志框架整体经历了如下图所示的演变历史,接下来就来看看吧~
这应该是最早的日志记录方式吧,缺点是:
在1996年初,E.U.SEMPER
(欧洲安全电子市场)项目决定编写自己的跟踪API
,最后该API演变为Log4j
,Log4j
日志软件包一经推出就备受欢迎,当然这里必须要提到一个人,就是Log4j
的主要贡献者,这个大佬:Ceki Gülcü。
这位大佬应该不能仅仅用大佬来称呼了,可能应该叫巨佬了!讲到后面你就慢慢明白了,后来Log4j
成为了Apache
基金会项目中的一员,同时Log4j
的火爆,让Log4j
一度成为业内日志标杆。(据说Apache
基金会还曾经建议Sun
引入Log4j
到java的标准库中,但是Sun
拒绝了)
果然Sun
有“自己的考虑”,2002年2月Java1.4发布,Sun
竟然推出了自己的日志库Java Util Logging
(JUL
),其实很多日志的实现思想也都是仿照Log4j
,毕竟Log4j
先出来很多年了,已经很成熟了此时,这两个日志工具打架,显然Log4j
是更胜一筹。
神仙打架其实就是互相竞争,Sun
心里可能在想,不就是做个日志工具嘛,谁不会!当然好景不长。
Apache
: 玩编程,谁玩的过我!你不让我成为JDK标准,我就自己成为日志标准!
于是JUL
刚出来不久,2002年8月Apache
又推出了日志接口Jakarta Commons Logging
(JCL
),也就是日志抽象层,当然也提供了一个默认实现Simple Log
,这野心很大,想一统日志抽象(就像以前的JDBC一统数据库访问层),让日志产品去实现它的抽象,这样只要你的日志代码依赖的是JCL
的接口,你就可以很方便的在Log4j
和JUL
之间做切换,当时日志领域大概是这样的结构,当然也还是方便理解的,也很优雅。
但是好景不长,在使用过程中,虽然现在日志系统在JCL
的统一下很优雅,很美好,但大家发现了JCL
还不够好,有些人甚至认为JCL
造成的问题比解决的问题还多…JUL
主要有三个缺点:(1)效率较低;(2)容易引发混乱;(3)使用了自定义ClassLoader的程序中,使用JCL
会引发内存泄露。
所以大佬出现,Ceki Gülcü(也就是Log4j
的作者)由于一些原因离开了Apache
,之后觉得JCL
不好,于是于2005年自己撸出一个新工程,也就是一套新日志接口(有得也叫日志门面):Slf4j
(Simple Logging Facade for Java
),感觉粗来了么,这战争的硝烟,明显这个Slf4j
是直指JCL
啊,但是后面确实也证明了Slf4j
是要比JCL
在很多地方更优秀。
Ceki Gülcü: 玩接口,我一个人就是一支军队!
但是由于Slf4j
出来的较晚,而且还只是一个日志接口,所以之前已经出现的日志产品,如JUL
和Log4j
都是没有实现这个接口的,所以尴尬的是光有一个接口,没有实现的产品也是很憋屈啊,就算开发者想用Slf4j
也是用不了,这时候,大佬发话了。
Ceki Gülcü: 别急,我早帮你们想好了,要让Sun
或者Apache
这两个庞然大物来实现我的接口,太南啦,老铁,但…我帮你们实现,不就完了么。
于是大佬Ceki Gülcü撸出了之前提到的桥接包,通过桥接包来帮助Slf4j
接口与其他日志库建立关系,这种方式称桥接设计模式。代码使用Slf4j
接口,就可以实现日志的统一标准化,后续如果想要更换日志实现,只需引入Slf4j
与相关的桥接包,再引入具体的日志标准库即可。
大佬提供了桥接包,于是日志系统现在有了这样的结构:
但是其实之前很多Java应用应该依赖的JCL
,所以光有日志产品桥接包,好像还不够。
Ceki Gülcü: 没问题,不就是桥接包么,我写,我来证明Slf4j
是最完美的。
于是有了JCL
的桥接包:
相当于此时的桥接包就是分了两种场景:(1)之前Java应用用的日志接口(如JCL
);(2)之前Java应用用的日志产品(如Log4j
)。
那我们如果再考虑一下这种场景呢?
假设你的Java应用使用了Spring的第三方的框架,但是假设Spring默认用JCL
,并且最终用的JUL
打印的日志,但是你的系统使用了Slf4j
作为日志接口,日志产品使用了Log4j
,那不出意外的话…你将有两种日志输出,两种日志的打印方式不统一,到时候解决bug的时候就很恼火,而且配置日志的配置文件还需要两份。
所以为了方便统一应用中的所有日志,大佬发话了。
Ceki Gülcü: 没事,大家都选择用Slf4j
统一吧,我来帮大家统一,没有事是桥接包解决不了的,有的话,那就再来个。
当然此时这种场景也是符合之前说的两种情况的,因此现在日志系统大体应该是这样的:
但是…但是看后边吧,大佬毕竟是大佬,Log4j
不就是自己写的么,所以最清楚Log4j
缺点的人也正是他。
Ceki Gülcü 巨佬觉得市场上的日志标准库都是间接实现Slf4j
接口,也就是说每次都需要配合桥接包,也就是之前的日志产品都不是正统的Slf4j
的实现。
因此在2006年,Ceki Gülcü 基于Slf4j
接口写出了Logback
日志标准库,做为Slf4j
接口的默认实现,Logback
也十分给力,在功能完整度和性能上超越了所有已有的日志标准库,其根本原因还在于,随着用户体量的提升,Log4j无法满足高性能的要求,成为应用的性能瓶颈。而且当时大佬还专门写了一篇文章:
是不是这太针对了…哈哈哈哈,就是这么无情,当然都是他写的,他肯定是最清楚这两者实现的区别。
毋庸置疑,Logback
是完美实现了Slf4j
,于是现在日志系统变成了:
现在有了2个日志接口,3个日志产品,大家也都看起来相安无事。但…Slf4j
+Logback
的模式,显然很冲击JCL
+Log4j
,并且本身Logback
确实比Log4j
性能更优,设计更为合理,所以,老东家Apache
可就坐不住了。
在2012年,Apache
直接推出新项目,不是Log4j1.x
升级,而是新项目Log4j2
,因为Log4j2
是完全不兼容Log4j1.x
的。
并且很微妙的,Log4j2
几乎涵盖Logback
所有的特性(这不是对着干是啥~而且还有抄袭的嫌疑哈哈哈),更甚者的Log4j2
也搞了分离的设计,分化成log4j-api
和log4j-core
,这个log4j-api
也是日志接口,log4j-core
才是日志产品。
现在我们可有了3个日志接口,以及4个日志产品。当然Apache
也知道该做啥,为了让大家可以接入自己的Log4j2
,那不就是桥嘛,Apache
也麻溜的推出了它的桥接包,所以日志系统变成了现在的局面:
了解了日志的发展历史,我们再回过头来思考一下,如果,你的系统在选择日志方案的时候,如何抉择呢?毕竟有3个日志接口,以及4个日志产品。
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>${log4j.version}version>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j-implartifactId>
<version>${log4j.version}version>
<scope>runtimescope>
dependency>
Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)