0.总体介绍
日志体系由三部分组成
- 日志门面接口
- 一系列绑定和桥接
- 具体的日志实现
所在的位置,如下图所示:
1.日志实现框架
- log4j 最广泛应用的日志框架,成为事实上的标准
- jul(java.util.logging) jdk1.4加入,为了对抗log4j,效率灵活性较差使用较少
- logback 基于slf4j-api接口实现,性能高于log4j
- log4j2 重写了log4j,性能高于log4j,logback
- 其他
注:log4j、logback、log4j2是同一个作者Ceki Gülcü
2.日志门面接口JCL和SLF4J
上面介绍了四种日志框架,到底用哪个日志框架,现在广泛应用的还是log4j,如果负载较高可以考虑使用logback和log4j2.
但是如果两个系统相互依赖,用的不同的日志框架,难道需要依赖两个日志框架么?
Apache和log4j的作者提供两种接口层面的汇总
- JCL(commons-logging)
- SLF4J(simple log facade for java)两个日志框架的门面。
提供了统一的日志抽象接口,适配和转接了各种日志框架,使用者只用调用抽象层统一的接口就行了。应用层不直接依赖实际的日志实现。
但是,问题又来了,怎么使用呢?
- 问题一:我的项目中准备使用SLF4J作为接口层面统一,使用logback 作为日志实现框架,但是我依赖了一些开源框架使用了log4j,或者JCL(commons-logging),那么怎么汇总?
- 我的项目中已经使用了log4j,但是依赖了一些开源框架使用了SLF4J,那么怎么转接SLF4J的实现到log4j呢?
这里拿SLF4J举例,JCL(commons-logging)同样适合场景。
3.桥接
问题一,先看一幅图
- 项目中打算使用SLF4J作为接口层,使用logback作为实现层
- 项目依赖的开源框架使用了Commons-logging,log4j,juc日志框架
- 使用jcl-over-slf4j桥接commons-logging
- 使用log4j-over-slf4j桥接log4j
- 使用jul-to-slf4j桥接jul(java.util.logging)
那么什么是桥接?
桥接的原理是把对应的门面日志接口重新实现了一遍,包名、类名、接口都一样,只是具体实现它委托给SLF4J了。
通过一系列桥接,它们把已存在的日志门面适配到SLF4J(jul-to-slf4j)。或者仿效已存在的日志门面或者实现(jcl-over-slf4j,log4j-over-slf4j,jul-to-slf4j)。
总结:
- 比如我们项目中依赖了spring-core,因为它原生依赖commons-logging,所以需要用jcl-over-slf4j桥接包来代替commons-logging把具体实现委托给slf4j
- 项目中要排除掉commons-logging
- 再依赖jcl-over-slf4j
- jcl-over-slf4j和commons-logging拥有相同的包名、类名、接口,从而达到桥接的效果
4.绑定
再看问题二,再来一幅图
- 项目中打算使用SLF4J作为接口层,使用log4j作为实现层(log4j并没有实现SLF4J接口)
- 项目依赖的开源框架使用了Commons-logging,juc日志框架
- 使用jcl-over-slf4j桥接commons-logging
- 使用jul-to-slf4j桥接jul(java.util.logging)
- slf4j-api绑定到slf4j-log412。基于一个已存在的日志框架来实现了SLF4J API
那么什么是绑定?
绑定的原理是因为slf4j-api中的LogFactory通过StaticLoggerBinder.getSingleton()获取具体实现logger,一个绑定包实现了org/slf4j/impl/StaticLoggerBinder.class,所以它们在编译时刻就绑定在一起,而绑定包中的StaticLoggerBinder类会绑定对应的实现。这部分看看源码就一目了然了。
5.总结&实现包附录
通过桥接和绑定就可以解决上述的问题。日志推荐使用做法是,使用SLF4J+logback,如果依赖了其他开源项目导致日志混乱,可以使用桥接的方式进行解决。
下面附录一下SLF4J桥接和绑定的包
SLF4J桥接
- jul-to-slf4j:jdk-logging到slf4j的桥接
- log4j-over-slf4j:log4j1到slf4j的桥接
- jcl-over-slf4j:commons-logging到slf4j的桥接
SLF4J绑定
- slf4j-jdk14:slf4j到jdk-logging的绑定
- slf4j-log4j12:slf4j到log4j1的绑定
- log4j-slf4j-impl:slf4j到log4j2的绑定
- logback-classic:slf4j到logback的绑定
- slf4j-jcl:slf4j到commons-logging的绑定