Java log框架使用指南

议题如下:

  • 引言
  • Java世界的log框架发展历程
  • 什么是绑定实现(bingding)
  • 什么是覆盖实现(override)
  • 什么是桥接适配(bridge/route)
  • 日志jar包之间的冲突
  • Spring-boot为我们做了什么?
  • Reference

引言

眼花缭乱的日志jar包,让我们无从下手

Java世界的log框架发展历程

  • 先来认识一个人Ceki Gulcu
  • https://github.com/ceki
  • Java世界所有的log框架都跟他有关系

通过时间线整理如下

时间线

日志名称

作者

简介

200118

log4j1

Ceki Gülcü/apache

jdk1.4之前广泛使用(是直接使用实现类,没有接口定义),并成为成为了Apache项目

200226

java.util.logging(jul

sun

sun拒绝把apachelog4j纳入到jdk并在jdk1.4版本之后新增了jul;没有接口api定义;java.util.logging.Logger

2002813

commons-logging(jcl

apache

鉴于市面上log4j1jul都广泛使用,但是两者之间的api完全不相同,无法快速切换。则抽象出一套log接口api定义,在运行时可以切换不同的日志实现组件

目前已经停止更新了。

2006

slf4j

Ceki Gülcü

虽然Ceki Gülcü认为抽象一套log接口的api定义是好的设计,但是他认为jcl的设计本身并不好用,于是自己开发出slf4j(Simple Logging Facade for Java)——同样也是不提供具体的log实现,只对外提供统一的接口/切面。目的就是要取代jcl

2006

logback

Ceki Gülcü

Ceki Gülcü同时基于slf4j的抽象,也开发出logback作为log的实现,性能比log4j好。目的就是要取代log4j1

20147

log4j2

apache

apache参考了logback的实现,推出了log4j2log4j2自身是接口+实现

通过log历史进程,总结如下

  • 两大日志接口:jcl(commons-logging),slf4j
  • 目前一统江湖的就是apache的commons-logging和slf4j,他两的作用就是提供统一的接口,而具体的日志实现交给底层绑定的具体的日志实现框架。这样一来,我们的业务系统中可以灵活的更换不同的日志实现,并且可以不需要去改动代码。
  • 对于开发者而言,每种日志都有不同的写法。如果我们以实现的日志框架来进行编写,代码就限制死了,之后就很难再更换日志系统,很难做到无缝切换。
  • 抽象与实现分离。

什么是绑定实现(bingding

JCL的绑定情况如下

接口名称

接口的jar

实现名称

实现的jar

实现的jar的含义

commons-logging(jcl

commons-logging.jar

logging(jul

jdk自带的日志实现

动态绑定

commons-logging.jar

log4j1(jcl亲儿子)

log4j.jar

log4j 一代版本就一个依赖jar,最高版本是12log4j一代默认实现了jclapi

spring

commons-logging.jar

log4j2

log4j-api.jar

定义的api

log4j-core.jar

api的实现

log4j-jcl.jar

log4j二代绑定到jcl;log4j二代默认实现的apilog4j-api.jar

logback默认不支持

默认不支持

logback是默认是基于slf4j实现

slf4j的绑定情况如下

接口名称

接口的jar

实现名称

实现的jar

实现的jar的含义

slf4j

slf4j-api.jar

logging(jul

slf4j-jdk14.jar

slf4j绑定到jdk-loggingjava.util.logging.Logger

静态绑定

slf4j-api.jar

log4j1

slf4j-log4j12.jar

slf4j绑定到log4j

log4j.jar

log4j 一代版本就一个依赖jar,最高版本是12

slf4j-api.jar

log4j2

log4j-slf4j-impl.jar

slf4j绑定到log4j2二代

注意,这个是apahce自己去实现的,并不是slf4j提供的

log4j-api.jar

log4j 二代版本的api

log4j-core.jar

log4j 二代版本的实现

slf4j-api.jar

logback(slf4j亲儿子)

logback-core.jar

logback的核心包

logback-classic.jar

logback默认实现了slf4jAPI

slf4j-api.jar

jcl

slf4j-jcl.jar

slf4j绑定到jcl

slf4j官网的介绍

  • Slf4j厂商并没有开发支持log4j2的绑定代理jarApache开发了基于log4j2绑定代理jarlog4j-slf4j-impl
  • 从maven仓库可以看到相关binding的字样

绑定实现的总结

jar包命名规则

abc-xyz.jar:把abc绑定到xyzabc作为接口存在,把实现绑定到xyz的实现上

使用场景

接口与实现之间的关系,就被当做一种绑定;

存量的项目中已经迁移到slf4j api上面来,但是发现一些场景必须使用其他的日志实现(jcl/log4j);

比如:配置文件不想修改,依赖的jar/项目里面直接使用了实现类,依赖的jar里面有配置文件等等;

————针对这种场景,需要的是一种绑定的概念,英文单词为bingding,把abc绑定到xyz
然后,再与加入该日志框架的具体实现
jar包;

提供商

通常情况下,由该接口的厂商提供;目的在于让自己所出品的接口作为统一接口,但是可以让用户选择业界不同的日志实现框架

结论:接口是slf4j,实现则是其他日志框架(自己出品的接口,可以支持别人去实现)

 什么是覆盖实现(override

使用场景

源日志框架

需要依赖jar

目标日志框架

jcl

jcl-over-slf4j.jar

slf4j

log4j1

log4j-over-slf4j.jar

slf4j

覆盖实现的总结

jar包命名规则

abc-over-xyzabc的实现被xyz覆盖掉;abc作为实现,可以被xyz的实现所覆盖掉———提供了相同的包.

使用场景

场景一,老项目的代码和配置是使用标准的api(接口+基础class),那么code+配置文件多是0修改。

场景二,新项目自身采用的是slf4j api日志框架,但是开发过程中依赖的组件(spring/框架,其内部已经采用了某种日志框架,并且这些组件/框架内容使用了面向接口编程(但不是slf4j接口);
针对实现层的替换(而不是并存),如果项目依赖了
overjar包,则需要排除掉之前的默认实现的jar包;
比如
spring就是使用jcl居多,而自己的项目使用的logback相关的log配置,让springjcl日志的实现层用slf4j的实现来替代,这样用一套logback的配置就可以打印spring的日志了;

提供商

slf4j提供,致力于为不同的接口定义,提供slf4j的搞性能实现。

结论:接口不是slf4j,实现则是slf4j(别人的亲儿子,我也要替换。)老接口,新实现,旧实现尽量排除

扩展内容,细节介绍

Override 为了实现覆盖的效果:是通过提供同名的包 . 类的方式 —— 去替换原先的 jar 包里面的包 . 类。
所以理论上 override jar 包,不可以与原先实现的 jar 包并存的,是要排除掉原先的 jar 包的
如果很难排除原先的 jar ,保证 override jar 优先被加载,也是可以的。
•Slf4j的亲儿子logback的具体实现,是一定要依赖的。
如果项目里面直接使用具体的实现子类,那么 override jar 包是失效的
通过 jar 的源码可以提高自身对 override的理解:打开log4j-1.2.17.jar与log4j-over-slf4j-1.7.30.jar你会发现他们包含了同名的包.类

 

什么是桥接适配(bridge/route)

使用场景

源日志框架

需要依赖jar

目标日志框架

实现的jar的含义

jul

jul-to-slf4j

slf4j

jul的实现桥接到slf4j的实现上

(Juljdk自带的,没办法排除jar包,只能做桥接)

log4j2

log4j-to-slf4j

slf4j

log4j2的实现桥接到slf4j的实现上

(项目里面用了log4j2apiSlf4j厂商并没有开发支持log4j2overridejar包。Apache厂商就自己开发。)

强调:选择“桥接适配”的方案,是只有当“ override ”方案不支持的时候,所选择的
到万不得已,不要选择该方案的 jar —— 该方案会导致 log 的性能大幅度下降
jar 包命名规则 abc -to-xyz abc 的实现被转发(桥接 / 路由 / 适配)到 xyz 实现
负责桥接的 jar 包与具体实现的 jar 包并存

官方对桥接适配的介绍

Log4j Bridge

https://logging.apache.org/log4j/2.x/log4j-to-slf4j/index.html

日志jar包之间的冲突

A

B

冲突原因

logback-classic.jar

log4j-slf4j-impl.jar

两者都是针对slf4j的实现,运行时不能同时存在;

log4j-to-slf4j.jar

log4j-slf4j-impl.jar

spring-bootlog框架校验机制。Spring-boot认为:在maven依赖上,如果依赖了log4j-to-slf4j.jar,则认定将log4j2的实现,交给slf4j了,那么就应该是走slf4j亲儿子去实现(logback);而依赖log4j-slf4j-impl.jar了意味着让log4j2作为slf4j的实现存在;

jcl-over-slf4j.jar

slf4j-jcl

jcl-over-slf4j.jar意味着用slf4j所提供的实现去覆盖jcl实现;

slf4j-jcl意味着用jcl的实现slf4j接口;

log4j-over-slf4j.jar

slf4j-log4j12

同上

jul-to-slf4j.jar

slf4j-jdk14

同上

Spring-boot为我们做了什么?

spring-boot-starter-log4j2

用途:项目中所有的日志框架,可以转换成——slf4j为接口,以log4j2实现。

GroupId

ArtifactId

简介 

org.springframework.boot

spring-boot-starter-log4j2

默认不推荐,因此默认不传递依赖,需要项目手动依赖;

用于让项目采用面向slf4j接口api编程,但是采用log4j2实现的场景

spring-boot-starter-logging

用途:项目中所有的日志框架,可以转换成——slf4j为接口,以logback为实现。

GroupId

ArtifactId

简介 

org.springframework.boot

spring-boot-starter-logging

默认推荐,默认传递依赖;如果不想依赖,则需要手动排除

总结

但是 spring-boot 所提供的两个 log 依赖,都不包含 Override jar
Override jar 包是用来适配的场景是: 接口不是 slf4j ,但是实现层可以是 logback
所以, spring-boot 所提供的两个 log 依赖,仅仅是支撑 slf4j 作为 api 的场景所需要的。

Reference

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值