写点什么

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:191143

评论

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

九章云极DataCanvas公司牵手国家超算互联网,实现算法与算力一体化服务

九章云极DataCanvas

SpringBoot混淆代码,防止反编译代码泄露

源字节1号

开源 软件开发 前端开发 后端开发 小程序开发

一文读懂Penpad 以 Fair Launch 方式推出的首个资产 PEN

BlockChain先知

2023,九章云极DataCanvas的澎湃时刻

九章云极DataCanvas

企业架构设计原则之理念领先性

凌晞

架构设计原则

AIGC 周报(2.26~3.03)

AIGC Weekly 周报

人工智能 AI AI应用 openai AIGC

Git 安全远程访问:SSH 密钥对生成、添加和连接步骤解析

小万哥

git 程序人生 编程语言 软件工程 后端开发

华为云低代码Astro企业应用 Astro Pro上线啦!

华为云PaaS服务小智

低代码 华为云 公测

牛市初期,Penpad 以 Fair Launch 方式推出首个资产 PEN

石头财经

大模型基础应用框架(ReACT\SFT\RAG)创新及零售业务落地

京东零售技术

人工智能 算法 大模型 agent ChatGPT

万字长文讲解关于LowCode你需要知道的一切

canonical

DDD 低代码 软件架构 可逆计算 Nop平台

华为云时习知&成都大学附属医院,打造“互联网+医疗”标杆

轶天下事

再聊对架构决策记录的一些思考

疯狂架构

架构设计实战 架构决策记录 ADR

我正在使用React Native (Expo) 开源一个精美的电商购物应用。

Geek_9da61c

产品设计 软件开发 开源中国 品牌设计

HttpMessageConverter添加java8 LocateTime时间转换

智慧源点

带你全方位体验 Amazon Connect

亚马逊云科技 (Amazon Web Services)

融云 IM 史无前例五折优惠!

融云 RongCloud

百度AI,能否“投”出未来?

自象限

百度 AI

一文读懂Penpad 以 Fair Launch 方式推出的首个资产 PEN

股市老人

基于高德地图的电子围栏、地图搜索嵌入

五陵散人

地图 高德地图 电子围栏

一文读懂Penpad 以 Fair Launch 方式推出的首个资产 PEN

加密眼界

如何将Word一键转PPT?收好这3个办公提效神器!

彭宏豪95

效率 PPT 在线白板 办公软件 AI工具

编程究竟难在哪?

算法的秘密

九章云极DataCanvas公司出席WBBA 2024宽带发展大会

九章云极DataCanvas

一文读懂Penpad 以 Fair Launch 方式推出的首个资产 PEN

股市老人

技术管理者如何避免被裁掉(1)

芃篙君

管理

作业12

大肚皮狒狒

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