该文章的参考资料
1.鲁班大叔JAVA的日志体系视频讲解
2.Java日志系统历史从入门到崩溃
一、混乱的Java日志体系
java主流日志框架的4种实现
- log4j
log4j就是log4j 1.x版本,最早期的日志框架,由巨佬Ceki Gülcü
大约在1996年
开发
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
- log4j2
log4j2就是log4j 2.x版本。巨佬Ceki Gülcü
之后将log4j捐赠给apache,apache接手开发的产品,是log4j的升级版
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
-
jul
Java Util Logging,2002年2
月Sun
推出jdk官方的日志实现,>=jdk1.4引入。
-
logback
由于使用Slf4j,如果采用之前的日志实现,需要一次桥接包,也就是之前的日志产品都不是正统的Slf4j的实现。因此,2006年
,出自Ceki Gülcü
之手的日志产品Logback应运而生
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
java主流的2种日志标准接口(适配器)
- jcl
2002年8月
,apache想成为日志的标准,所以撸了一套标准接口java commons loging
,并给出了一套默认实现Simple Log
。jcl它只提供日志接口,具体实现在运行时动态寻找对应组件。
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
- slf4j
2005年
大佬Ceki Gülcü
觉得jcl不够好,所以自己又撸了个标准接口Slf4j。
slf4j全称 Simple Logging Facade for Java(简单日志门面),与jcl类似本身不替供日志具体实 现,只对外提供接口。与jcl不同的是其采用在classPath加入适配器jar包来表示具体采用哪种实现。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
Spring采用什么日志实现
假如我们开发一个类似于Spring的框架,那我们的框架要用什么日志框架实现?log4j、logback,还是都不能用?答案是都不能用!
比如如果Spring用了log4j去打印,第三方项目引入了Spring,项目自己却用log4j2来打印,则日志文件会有两份(注意是日志被拆分打印到两份日志中而不是一条日志打印两次)。Spring的日志会有一份,比如log4j2.x.log;项目自己打的日志会有一份,输出文件为log4j1.x.log。当我们要排查bug的时候,可能要还去看两份日志!这是不能忍受的!
所以Spring只能采用日志适配器(标准接口)来实现,而Spring初期的时候是只有jcl没有slf4j的,所以Spring采用的是jcl
。
使用志适配器(标准接口)来实现的好处是,你项目具体用的是什么日志实现(这些日志实现要实现标准接口)我不管,Spring可以通过某种机制绑定到Spring中。
桥接器
后面巨佬Ceki Gülcü
为了让别人使用slf4j,所以又撸了很多套桥接器,让其他实现桥接到slf4j上。
二、总结
混乱的原因
其实日志这么混乱,主要就是三个巨佬在相爱相杀造成的!所以不要搞三角恋呀!
巨佬Ceki Gülcü
创建出log4j,后面贡献给apache
,然后apache
建议sun
将log4j纳入jdk,sun
不同意并自己搞了一套juc。
然后apache
就不服气,既然你不采纳我的建议让log4j称为标准,那我就写一套标准接口来使它称为行业标杆,所以就出来了jcl。
后面巨佬Ceki Gülcü
又觉得jcl不好,站出来了,撸了一套更加好的slf4j。但是由于在slf4之前很多系统已经采用了log4j、juc等实现,很多人都不用slf4j。巨佬Ceki Gülcü
后面为了证明slf4j是最好的,为了让别人用slf4j,所以又撸了很多套桥接器,让之前使用log4j、juc等的系统可以桥接过来使用slf4j!
em…所以现在日志的版图是这样的= =是不是比战国时期的版图还乱!!!
最佳实践
了解了日志的发展历史,那现在我们再回过头来看看如果,你的系统在选择日志方案的时候,如何抉择呢?毕竟我们3个日志接口,以及4个日志产品
-
显然第一点是使用日志接口的
API
而不是直接使用日志产品的API
这一条也是必须的,也是符合依赖倒置原则的,我们应该依赖日志的抽象,而不是日志的实现 -
日志产品的依赖只添加一个
当然也这个也是必须的,依赖多个日志产品,只会让自己的应用处理日志显得更复杂,不可统一控制 -
把日志产品的依赖设置为
Optional
其中Optional
是为了依赖不会被传递,比如别的人引用你这个jar,就会被迫使用不想用的日志依赖。当然,别人也可以通过exclusions来排除依赖!
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
三、留下的疑问
- 适配和桥接有什么区别?
- jul是怎么静态绑定实现的?
- slf4j是怎么绑定其实现的?
- 桥接器是怎么让其他框架桥接到slf4j的?