【Java日志系列】JCL、SLF4J日志门面

news2024/11/23 18:29:40

目录

前言

一、日志门面概述

1. 门面模式(外观模式)

2. 日志门面

二、JCL

1. JCL组件结构

2. JCL案例

三、SLF4J

1. SLF4J简介

2. SLF4J桥接技术

3. 快速入门

4. SLF4J集成日志实现

4.1 集成nop

4.2 集成Logback

4.3 集成Log4j

4.4 集成JUL 

4.5 同时集成多个日志实现

 5. SLF4J桥接器的使用

总结

 


前言

  在软件开发过程中,日志记录是一项至关重要的任务,它不仅有助于开发人员调试和追踪问题,还能帮助运维团队监控系统健康状况。然而,不同的日志框架有着不同的API,这导致应用程序在切换日志框架时需要修改大量代码,增加了维护成本。为了解决这一问题,门面模式被引入到日志管理中,通过创建一个统一的接口来降低应用程序与底层日志框架之间的耦合度。本文将探讨两种常见的日志门面——JCL (Jakarta Commons Logging) 和 SLF4J (Simple Logging Facade for Java),并介绍它们是如何简化日志管理的。

一、日志门面概述

1. 门面模式(外观模式)

  我们先谈一谈GoF23种设计模式其中之一。门面模式,也称为外观模式,其核心为:外部一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。外观模式主要体现了Java中的一种好的封装性。更简单的说,就是对外提供的接口要尽可能的简单。

2. 日志门面

  每一种日志框架都有自己单独的API,要使用对应的框架就要使用其对应的API,这就大大的增加应用程序代码对日志框架的耦合性。为了解决这个问题,就是在日志框架和应用程序之间架设一个沟通的桥梁,对于应用程序来说,无论底层的日志框架如何改变,都不需要任何感知。只要门面服务做的足够好,随意换另外一个日志框架,应用程序不许哟啊修改任意一行代码,就可以直接上线。我们去餐厅吃饭,需要和前台进行一个沟通,日志门面就相当于这里的前台。

补充:常见的日志框架及日志门面

常见的日志实现:JUL、log4j、logback、log4j2

常见的日志门面:JCL、slf4j

出现顺序:log4j --> JUL --> JCL --> slf4j --> logback --> log4j2

二、JCL

  JCL全称为Jackarta Commons Logging,是Apache提供的一个通用日志API。用户可以自由选择第三方的日志组件作为具体实现,项log4j。,或者jdk自带的JUL,common-loggin会通过动态查找的机制,在程序运行时自动找出真正使用的日志库。当然,common-loggin内部有一个Simple logger的简单实现,但是功能很弱。所以使用common-loggin,通常都是配合着log4j以及其他日志框架来使用。使用它的好处就是,代码依赖是common-loggin而非log4j的API,避免了和具体的日志API直接耦合,在有必要时,可以更改日志实现的第三方库。

  JCL有两个基本的抽象类:

  • Log:日志记录器
  • LogFactory:日志工厂(负责创建Log实例。

1. JCL组件结构

2. JCL案例

  首先,我们导入JCL的依赖:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

  同时,导入junit测试后编写如下代码的程序:

@Test
public void test() {
    Log log = LogFactory.getLog(JCLTest.class);
    log.info("info信息");
}

   运行结果如下图所示:

JCL使用原则:如果有log4j,优先使用log4j,如果没有任何第三方日志框架的时候,我们使用的就是JUL 。

三、SLF4J

1. SLF4J简介

  简单日志门面SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交给其他日志框架,例如log4j和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架(log4j、logback等),中间使用桥接器完成桥接。所以我们可以得出SLF4J最重要的两个功能就是对于日志框架的绑定以及日志框架的桥接。

2. SLF4J桥接技术

  通常,我们依赖的某些组件依赖于SLF4J以外的日志API。我们可能还假设这些组件在不久的将来不会切换到SLF4J。为了处理这种情况。SLF4J附带了几个桥接模块,这些模块会将对log4j、JCL和java.util.logging API的调用重定向行为,就好像是对SLF4J API进行的操作一样。

3. 快速入门

  导入SLF4J相关依赖:

<!-- slf4j日志门面核心依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.13</version>
</dependency>
<!-- sl4j自带的简单日志实现 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.13</version>
</dependency>

  编写如下代码: 

Logger logger = LoggerFactory.getLogger(this.getClass());
String msg = "你好,世界!";
logger.info("message:{}", msg); // 动态输出字符串信息

补充:对于异常对象e的打印,我们不需要用{}来进行字符串拼接。示例:

Logger logger = LoggerFactory.getLogger(this.getClass());
try {
    Class.forName("aaa");
} catch (ClassNotFoundException e) {
    logger.error("具体错误是:", e);
}

  运行结果如下: 

补充:SLF4J对日志的级别划分为trace、debug、info、warn、error五个级别。

注意:在没有任何其他日志实现框架集成的基础上,SLF4J使用的是自带的框架slf4j-simple,slf4j-simple也必须以单独依赖的形式导入进来。

4. SLF4J集成日志实现

  有以下三种情况对日志实现进行绑定:

  1. 在没有绑定任何日志实现的基础之上,日志是不能够绑定实现任何功能的。值得大家注意的是,slf4j-simple是slf4j官方提供的,使用的时候,也是需要导入依赖,自动绑定到slf4j门面上;如果不导入,slf4j核心依赖是不提供任何实现的。
  2. logback和simple(包括nop)都是slf4j门面时间线后面提供的日志实现,所以API完全遵循slf4j进行的设计,那么我们只需要导入想要使用的日志实现依赖,即可与slf4j无缝衔接。值得一提的是,nop虽然也划分到实现中了,但是它是指不实现日志记录。
  3. log4j和JUL 都是slf4j门面时间线前面的日志实现,所以API不遵循slf4j进行设计,通过适配的技术,完成的日志门面的衔接。

4.1 集成nop

  slf4j-nop 表示不记录日志,在我们使用slf4j-nop的时候,首先还是需要导入实现依赖:

<!-- sl4j的nop -->
<dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-nop</artifactId>
     <version>2.0.13</version>
</dependency>

  对于nop来说,控制台不会打印任何日志。 

4.2 集成Logback

  集成Logback同样需要导入依赖,其导入方式与相关测试的运行结果如下所示:

<!-- logback日志实现  logback-classic已经涵盖logback-core这个依赖了 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.5.6</version>
</dependency>

4.3 集成Log4j

  对于Log4j来说,其出现时间在SLF4J之前,所以SLF4J需要使用适配器集成Log4j。相关依赖与相关测试的结果如下所示:

<!-- 导入log4j适配器依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>2.0.13</version>
</dependency>
<!-- log4j依赖 -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

4.4 集成JUL 

  与Log4j一样,JUL也需要导入相关的适配器依赖,由于JUL是Java自带的日志框架,所以导入适配器后不需要再导入其他依赖。相关依赖与相关测试的结果如下所示:

<!-- 导入jul适配器依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>2.0.13</version>
</dependency>

注意:以上四个集成前提是均需要先导入slf4j日志门面核心依赖即slf4j-api。

4.5 同时集成多个日志实现

  当我们导入了多个日志实现依赖时,SLF4J会在控制台打印出有多个日志实现的警告信息。那么,在集成了多个日志实现的情况下,我们会优先使用哪一个日志实现呢?对于导入的多个日志实现依赖,哪一个日志实现依赖书写靠前,就使用哪一个日志实现,具体示例如下:

 5. SLF4J桥接器的使用

  通常,我们在项目开发中使用的日志组件依赖于日志记录 SLF4J 以外的 API,我们可以假设这些组件会在不久的将来切换到 SLF4J。在这种情况下,SLF4J 随附多个桥接模块重定向对 log4j 1.x、JCL 和 java.util.logging API 的调用,表现得好像它们是针对 SLF4J API 制作的。下图说明了这个想法(图片来自官网):

  假设我们项目中使用的日志框架是Log4j,现在随着业务的变更,我们需要将日志框架转换成SLF4J + Logback 的一个日志组合,那么我们怎么才能在不惊动原先代码的情况下,对日志进行一个转换呢?我们需要将原型的Log4j依赖注释掉,导入SLF4J核心依赖、针对于Log4j的桥接器和Logback日志实现依赖,就能在不惊动原来代码的情况下,对日志进行一个转换了。

<!-- log4j依赖 -->
<!-- <dependency> -->
<!--     <groupId>log4j</groupId> -->
<!--     <artifactId>log4j</artifactId> -->
<!--     <version>1.2.12</version> -->
<!-- </dependency> -->
<!-- slf4j日志门面核心依赖 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.13</version>
</dependency>
<!-- log4j桥接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>2.0.13</version>
</dependency>
<!-- logback日志实现  logback-classic已经涵盖logback-core这个依赖了 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.5.6</version>
</dependency>

   同样的一段代码,在转换前与转换后的日志输出格式如下图所示:

注意:适配器和桥接器不能一起导入。桥接器如果在适配器之前导入,则运行报错;桥接器如果在适配器之后导入,则不会执行桥接器(执行适配器),没有任何意义。

总结

  通过使用这些日志门面,开发者可以在不影响现有代码的情况下轻松更换日志框架,极大地提高了应用的可维护性和可扩展性。总之,无论是选择 JCL 还是 SLF4J,都可以显著减少因日志框架变化带来的代码改动,提高开发效率,同时保持系统的稳定性和可维护性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2062055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文彻底搞懂Transformer - 总体架构,零基础入门到精通,收藏这一篇就够了

Transformer 一、RNN编码器-解码器架构**** ********序列到序列模型&#xff08;Seq2Seq&#xff09;&#xff1a;Seq2Seq模型的目标是将一个输入序列转换成另一个输出序列&#xff0c;这在多种应用中都具有广泛的实用价值&#xff0c;例如语言建模、机器翻译、对话生成等。 …

网络及ipc内存共享

大字符串找小字符串 调试 1. 信号处理函数注册&#xff1a;•一旦使用 signal 函数注册了信号处理函数&#xff0c;该函数就会一直有效&#xff0c;直到程序结束或者显式地取消注册。2. 注册多次的影响&#xff1a;•如果多次注册同一信号的处理函数&#xff0c;最后一次注册的…

Java 入门指南:List 接口

Collection 接口提供了一系列用于操作和管理集合的方法&#xff0c;包括添加、删除、查询、遍历等。它是所有集合类的根接口&#xff0c;包括 List、Set、Queue 等。 Collection 接口常见方法 add(E element)&#xff1a;向集合中添加元素。 addAll(Collection col)&#xff1…

打架检测算法在公共安全中的创新应用

在现代社会中&#xff0c;公共场所的安全问题日益受到重视&#xff0c;特别是暴力事件的监控和预防更是各类安防系统的核心需求之一。随着视频监控设备的普及&#xff0c;如何从大量监控数据中实时、高效地识别出潜在的暴力行为&#xff0c;成为亟待解决的难题。传统的视频监控…

怎么对前端的一些按钮做一个权限校验

在一般情况下,我们需要对一些按钮做一个权限校验,来保证只有有权限的用户才能看到 1.创建一个js文件,来写我们的全局方法 我的方法是这样的 import Vue from vue;Vue.mixin({methods:{hasAuth(perm) {var authority this.$store.state.menu.permList;if (authority.indexOf(…

JointJs 在 Vue 中的使用探索(一): Hello JointJS

文章目录 前言根本问题探索过程安装 jointjs测试 joint/core demo 代码jointjs joint/core 前言 最近需要用到 JointJs 做一些东西&#xff0c;但是 官方文档 的 joint/core 跑下来后发现并不太好使&#xff0c;空白一片…&#xff08;这是个误会…&#xff09; 所以开了个贴给…

map与set容器初识:初步运用map与set

前言&#xff1a; 本文主要讲解的时对于map与set容器的初步使用&#xff0c;希望大家对map与set容器不熟悉的看了之后可以快速运用set与map到日常中来。&#xff08;本文适合对vector等基础容器有一定基础的同学&#xff09; 一、set与map容器常见接口 迭代器接口与以往的所…

【hot100篇-python刷题记录】【不同路径】

R5-多维动态规划篇 多维动态规划的核心在于建立多维状态记录表。 本题中&#xff0c;建立dp二维数组表&#xff08;初始化为1&#xff09; dp[i][j]dp[i-1][j]dp[i][j-1] 注意&#xff0c;需要判断是否存在&#xff0c;因为二维数组有边界 第一种处理需要判断边界 第二种&…

go的defer机制

defer的底层机制 为栈操作&#xff0c;栈是一个先进后出的数据结构 func main() {fmt.Println("reciprocal")for i : 0; i < 10; i {defer fmt.Println(i)} }运行结果 reciprocal 9 8 7 6 5 4 3 2 1 0defer拷贝机制 以下已经发生压栈发生值拷贝数据不再会发生变…

【Python机器学习系列】一文教你绘制多分类任务的ROC曲线-宏平均ROC曲线(案例+源码)

这是我的第345篇原创文章。 一、引言 ROC曲线是用于评估二分类模型性能的工具&#xff0c;它展示了模型在不同阈值下的真阳性率与假阳性率之间的关系&#xff0c;但是标准的ROC并不能运用于多分类任务种&#xff0c;于是扩展出了宏平均ROC曲线。 宏平均ROC曲线是多分类问题中…

工业控制常用“对象“数据类型汇总(数据结构篇)

合理巧妙的数据结构会大大简化项目的编程工作量,所以任何项目前期第一步应该是设计巧妙的数据结构、封装对象属性。这样会使我们的编程快捷和高效。这篇博客作为数据类型汇总,会不间断更新。 1、普通电机轴对象 2、普通电机轴对象(详细结构变量) TYPE "udtMotorAxis&q…

机器学习的入门笔记(第十五周)

本周观看了B站up主霹雳吧啦Wz的图像处理的课程&#xff0c; 课程链接&#xff1a;霹雳吧啦Wz的个人空间-霹雳吧啦Wz个人主页-哔哩哔哩视频 下面是本周的所看的课程总结。 利用GoogLeNet进行图像分类 GoogLeNet是由 Google 提出的卷积神经网络架构&#xff0c;于 2014 年在 …

没有用的小技巧之---接入网线,有内网没有外网,但是可以登录微信

打开控制面板&#xff0c;找到网络和Internet 选择Internet选项 点击连接&#xff0c;选择局域网设置 取消勾选代理服务器

JetBrains CLion 2024.2 (macOS, Linux, Windows) - C 和 C++ 跨平台 IDE

JetBrains CLion 2024.2 (macOS, Linux, Windows) - C 和 C 跨平台 IDE JetBrains 跨平台开发者工具 请访问原文链接&#xff1a;https://sysin.org/blog/jetbrains-clion/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Jet…

实战勤务指挥系统解决方案

4. 总体设计方案 方案围绕业务需求、接口需求和安全需求进行设计&#xff0c;包括语音集成、视频图像集成和第三方系统集成&#xff0c;以实现多系统联动和资源共享。 5. 系统特色 系统特色包括高度融合的指挥应用模式、简化的指挥流程、高效的管理机制&#xff0c;以及基于…

《Windows PE》2.1 初识PE文件

Windows PE文件&#xff08;Portable Executable file&#xff09;是一种可执行文件格式&#xff0c;用于Windows操作系统中的可执行程序、动态链接库&#xff08;DLL&#xff09;和驱动程序等。它是一种规范化的文件格式&#xff0c;定义了文件的结构和组织方式&#xff0c;以…

go设计模式———抽象工厂模式

抽象工厂模式概念 抽象工厂模式是一种设计模式&#xff0c;它允许创建一系列相关的对象&#xff0c;而无需指定具体的类。具体来说&#xff0c;抽象工厂定义了用于创建不同产品的接口&#xff0c;但实际的创建工作则由具体的工厂类完成。每个具体工厂负责创建一组相关的产品&am…

谷歌账号停用后申诉了,也收到了谷歌的邮件,如何判断谷歌申诉是否成功,成功了怎么办?被拒绝谷歌账号就废了吗?

似乎是谷歌分工机制的更新&#xff0c;最近谷歌账号“被停用”的情况貌似多了起来&#xff0c;许多朋友在谷歌账号提示活动异常&#xff0c;要输入手机号码恢复账号的时候&#xff0c;无论是否立刻恢复&#xff0c;很快好像就迎来了“您的账号已停用”的结果。或者有一些朋友许…

多元统计分析——基于R语言的单车使用情况可视化分析

注&#xff1a;基于R语言的单车使用情况可视化分析为实验记录&#xff0c;存在不足&#xff0c;自行改进。 一、提出问题&#xff08;要解决或分析的问题&#xff09; 1 、用户对共享单车的使用习惯&#xff0c;环境对共享单车运营带来的影响&#xff1f; 2 、共享单车的租赁…

【北京仁爱堂】痉挛性斜颈的健康指导

痉挛性斜颈是一种肌肉紧张异常症&#xff0c;仅限于颈部肌肉的肌张力障碍。当患者患有痉挛性斜颈&#xff0c;会表现为颈部肌肉间歇性或持续不规则的收缩&#xff0c;因此患者的头颈部会出现扭曲、歪斜、姿势异常等症状&#xff0c;多发于30-40岁左右中年人 一、 痉挛性斜颈的5…