QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

Java 常用日志框架介绍(下)

  • 2019-09-24
  • 本文字数:3315 字

    阅读完需:约 11 分钟

Java常用日志框架介绍(下)

8.3 Slf4j 调用过程源码分析,加入 slf4j-api-version.jar,与 Logback 组件

Slf4j 作为门面采用 Logback 作为实现或者采用其它上面提到过的组件作为实现类似,这里只分析采用 Logback 组件作为实现

8.3.1 示例代码

https://github.com/chlsmile/slf4j-logback-demo

8.3.2 pom 核心配置如下

 1<dependencies> 2    <dependency> 3      <groupId>org.slf4j</groupId> 4      <artifactId>slf4j-api</artifactId> 5      <version>1.7.13</version> 6    </dependency> 7    <!--logback-classic依赖logback-core,会自动级联引入--> 8    <dependency> 9      <groupId>ch.qos.logback</groupId>10      <artifactId>logback-classic</artifactId>11      <version>1.2.3</version>12    </dependency>13  </dependencies>
复制代码

8.3.3 程序入口类同上

8.3.4 源码追踪分析

1)、2)、3)、4)同上


5)调用 LoggerFactory 的


findPossibleStaticLoggerBinderPathSet()方法获取 StaticLoggerBinderPath 集合



6)调用 LoggerFactory 的 bind()方法的 staticLoggerBinderPathSet 集合对象赋值



7)在 LoggerFactory 的 bind()方法中调用 loback 包下的 StaticLoggerBinder 创建单例对象



8)在 LoggerFactory 的 bind()方法中调用 reportActualBinding()记录日志加载信息




9)LoggerFactory 中 INITIALIZATION_STATE 的值为 SUCCESSFUL_INITIALIZATION,调用 StaticLoggerBinder 的单例对象获取 ILoggerFactory




10)此时 LoggerFactory 中的 getLogger()方法中获取到的 ILoggerFactory 实际上是 logback jar 下的 LoggerContext



11)此时 LoggerFactory 调用 getLogger()方法获取到的 Logger 实际上是 logback jar 下的 Logger



8.4 Slf4j 调用过程源码分析,加入 slf4j-api-version.jar,同时加入多种日志实现组件

在项目中如果用 slf4j-api 作为日志门面,有多个日志实现组件同时存在,例如同时存在 Logback,slf4j-log4j12,slf4j-jdk14,slf4j-jcl 四种实现,则在项目实际运行中,Slf4j 的绑定选择绑定方式将有 Jvm 确定,并且是随机的,这样会和预期不符,实际使用过程中需要避免这种情况。

8.4.1 示例代码

https://github.com/chlsmile/slf4j-logback-log4j-demo

8.4.2 pom 核心配置如下

 1 <dependencies> 2    <dependency> 3      <groupId>junit</groupId> 4      <artifactId>junit</artifactId> 5      <version>4.11</version> 6    </dependency> 7    <dependency> 8      <groupId>org.slf4j</groupId> 9      <artifactId>slf4j-log4j12</artifactId>10      <version>1.7.25</version>11    </dependency>12    <dependency>13      <groupId>ch.qos.logback</groupId>14      <artifactId>logback-classic</artifactId>15      <version>1.2.3</version>16    </dependency>17    <dependency>18      <groupId>org.slf4j</groupId>19      <artifactId>slf4j-jdk14</artifactId>20      <version>1.7.25</version>21    </dependency>22    <dependency>23      <groupId>org.slf4j</groupId>24      <artifactId>slf4j-jcl</artifactId>25      <version>1.7.25</version>26    </dependency>27  </dependencies>
复制代码

8.4.3 程序入口类同上

8.4.4 源码追踪分析

基本步骤同上,这里只追踪主要不同点


1)追踪 LoggerFactory 的 bind()方法内部调用 findPossibleStaticLoggerBinderPathSet()方法后,从 classpath 下 4 个 jar 包内找到 StaticLoggerBinder



2)此时 LoggerFactory 的 bind()方法内部调用 reportMultipleBindingAmbiguity()方法,给出警告信息 classpath 下同时存在多个 StaticLoggerBinder,JVM 会随机选择一个 StaticLoggerBinder


9 桥接遗留的 api

在实际环境中我们经常会遇到不同的组件使用的日志框架不同的情况,例如 Spring Framework 使用的是日志组件是 Commons Logging,XSocket 依赖的则是 Java Util Logging。当我们在同一项目中使用不同的组件时应该如果解决不同组件依赖的日志组件不一致的情况呢?现在我们需要统一日志方案,统一使用 Slf4j,把他们的日志输出重定向到 Slf4j,然后 Slf4j 又会根据绑定器把日志交给具体的日志实现工具。Slf4j 带有几个桥接模块,可以重定向 Log4j,JCL 和 java.util.logging 中的 Api 到 Slf4j。

9.1 遗留的 api 桥接方案

9.2 桥接方式参见下图

9.3 使用 Slf4j 桥接要注意事项

在使用 Slf4j 桥接时要注意避免形成死循环,在项目依赖的 jar 包中不要存在以下情况。


9.4 遗留 api 桥接死循环源码分析源码

这里以项目中集成 log4j-over-slf4j 与 slf4j-log4j12 为例,其它组合形成死循环原理相类似。

9.4.1 示例代码

https://github.com/chlsmile/slf4j-Infinite-loop-demo

9.4.2 程序入口类同上

9.4.3 源码追踪分析

基本步骤同上,调用链路 LoggerFactory.getLogger()>LoggerFactory.getILoggerFactory()> LoggerFactory.performInitialization()>LoggerFactory.bind()


1)LoggerFactory.bind()方法内部调用 StaticLoggerBinder.getSingleton()获取 StaticLoggerBinder 实例



2)StaticLoggerBinder 调用构造方法内部调用 Log4jLoggerFactory 构造方法创建 ILoggerFactory



3)Log4jLoggerFactory 加载内部 static 代码块,校验出 classpath 下存在 org.apache.log4j.Log4jLoggerFactory,抛出异常


10 排除第三方日志依赖

在实际使用过程中,项目会根据需要引入一些第三方组件,例如常用的 Spring,而 Spring 本身的日志实现使用了 Commons Logging,我们又想使用 Slf4j+Loback 组合,这时候需要在项目中将 Commons Logging 排除掉,通常会用到以下 3 种方案,3 种方案各有利弊,可以根据项目的实际情况选择最适合自己项目的解决方案。

10.1 方案一 采用 maven 的 exclusion 方案

 1<dependency> 2    <groupId>org.springframework</groupId> 3    <artifactId>spring-core</artifactId> 4    <exclusions> 5        <exclusion> 6            <groupId>commons-logging</groupId> 7            <artifactId>commons-logging</artifactId> 8        </exclusion> 9    </exclusions>10    <version>${springframework.version}</version>11</dependency>
复制代码


这种方案优点是 exclusion 是 maven 原生提供的,不足之处是如果有多个组件都依赖了 commons-logging,则需要在很多处增加,使用起来不太方便。

10.2 方案二 在 maven 声明 commons-logging 的 scope 为 provided

 1<dependency> 2  <groupId>commons-logging</groupId> 3  <artifactId>commons-logging</artifactId> 4  <version>1.1.1</version> 5  <scope>provided</scope> 6</dependency> 7<dependency> 8  <groupId>org.slf4j</groupId> 9  <artifactId>jcl-over-slf4j</artifactId>10  <version>1.8.0-beta2</version>11</dependency>
复制代码


这种方案在调试代码时还是有可能导致 IDE 将 commons-logging 放置在 classpath 下,从而导致程序运行时出现异常。

10.3 方案三 在 maven 私服中增加类似于 99.0-does-not-exist 这种虚拟的版本号

 1<dependency>     2    <groupId>commons-logging</groupId>     3    <artifactId>commons-logging</artifactId>     4    <version>99.0-does-not-exist</version>     5</dependency>  6<dependency> 7  <groupId>org.slf4j</groupId> 8  <artifactId>jcl-over-slf4j</artifactId> 9  <version>1.8.0-beta2</version>10</dependency> 
复制代码


这种方案好处是声明方式比较简单,用 IDE 调试代码时也不会出现问题,不足之处是 99.0-does-not-exist 这种版本是 maven 中央仓库中是不存在的,需要发布到自己的 maven 私服中。

11 总结

由于历史原因 JDK 自身提供的 Log 组件出现的较晚,导致 Jdk 提供 Log 组件时第三方社区的日志组件已经比较稳定成熟。经过多年的发展 Slf4j+Logback 与组合,Commons Logging 与 Log4j 组合两大阵营已经基本成为了 Java 项目开发的标准,建议在新的项目开发中从这两种方案中选择适合自己项目的组合方案。


作者介绍:


圣卡西(企业代号名),目前负责贝壳找房 java 后台开发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/FWnh71eN5jxiu7aBOiUHaA


2019-09-24 18:191127

评论

发布
暂无评论
发现更多内容

首批通过 | 百度通过中国信通院H5端人脸识别安全能力评估工作

百度安全

硅纪元AI应用推荐 | 5分钟搞定会议纪要,一键生成脑图

硅纪元

通义听悟

Rust下SM4/AES/RSA加解密

dlzht

rust rsa AES SM4 RustCrypto

ByteSRC奖励再升级,抖音单个漏洞奖金提升至20万元

科技热闻

支出这么多?收入从何而来

源字节1号

小程序 开源 前端 后端

2024年第二季度 DDoS 威胁趋势报告

网络安全服务

TCP udp DDoS Cloudflare DDoS 攻击

tuxera手动批准内核扩展 如何手动批准其内核扩展 Tuxera Ntfs for mac内核扩展批准不了怎么办

阿拉灯神丁

Mac 内核 磁盘管理 Tuxera NTFS2023\ Tuxera NTFS教程

直播预告丨如何抓住“数字经济发展红利”,重塑企业可持续竞争能力?

轶天下事

智能运维新课程丨雅菲奥朗“可观测性国际认证课程”圆满结束

雅菲奥朗

可观测性 Observability SRE培训 SRE考试 SRE认证

汽车行业看板实战培训顺利举行

雅菲奥朗

看板 价值流 VSM

行人、司机和“萝卜”的城市路权争夺战,谁能赢?

脑极体

AI

面试阿里,直呼太难了!

王中阳Go

Go 后端 面经

IoTDB 分段查询语句详解:GROUP BY + 时序语义

Apache IoTDB

比亚迪王传福对话九牧林孝发,一场火出圈的“科技跨界”

Alter

使用 Elasticsearch Python SDK 查询 Easysearch

极限实验室

Python elasticsearch easysearch

IDEA插件—激活JRebel

源字节1号

小程序 开源 前端 后端

同样是人工智能 客户在哪儿AI和GPT等大模型有什么不同

客户在哪儿AI

ToB营销 ToB增长 大客户营销

最新资讯!《可观测性能力建设指南(2024年)》即将在2024可信云大会上发布!

乘云数字DataBuff

白皮书 可观测 信通院

开启SRE技术新篇章:SRE Foundation认证培训圆满结课

雅菲奥朗

SRE SRE培训 SRE考试 SRE认证

业务连续性专题:一致性和并发度的平衡

agnostic

高并发 一致性

Java常用日志框架介绍(下)_文化 & 方法_圣卡西_InfoQ精选文章