java日志门面之JCL和SLF4J
文章目录
- 前言
- 一、JCL
- 1、JCL简介
- 2、快速入门
- 3、 JCL原理
- 二、SLF4J
- 1、SLF4J简介
- 2、快速入门
- 2.1、输出动态信息
- 2.2、异常信息的处理
- 3、绑定日志的实现
- 3.1、slf4j实现slf4j-simple和logback
- 3.2、slf4j绑定适配器实现log4j
- 4、桥接旧的日志框架
- 4.1、log4j日志重构为slf4j+logback的组合
前言
什么时日志门面?
随着系统开发的进行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制。借鉴JDBC的思想
,为日志系统也提供一套门面,那么我们就可以面向这些接口规范来开发
,避免了直接依赖具体的日志框架。这样我们的系统在日志中,就存在了日志的门面
和日志的实现
。
常见的日志框架及日志门面
- 常见日志门面:JCL、slf4j
- 常见日志实现:JUL、log4j、logback、log4j2
- 框架诞生顺序:log4j --> JUL -->
JCL
-->slf4j
--> logback --> log4j2
日志门面和日志实现的关系
一、JCL
1、JCL简介
- 全称为
Jakarta Commons Logging
,是Apache
提供的一个通用日志API common-logging
会通过动态查找
的机制,在程序运行时自动找出log4j,或者jdk自带的jul- 使用它的好处就是,代码依赖是common-logging而非log4j的API, 避免了和具体的日志API直接耦合,在有必要时,可以更改日志实现的第三方库(
不改变代码,只修改依赖
) - JCL有两个基本的抽象类:Log(日志记录器),LogFactory(日志工厂负责创建Log实例)
2、快速入门
jcl依赖
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version>
</dependency>
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;public class JCLTest {@Testpublic void test01() {Log log = LogFactory.getLog(JCLTest.class);log.info("info");}
}
只导入
commons-logging
的输出结果
- 此时没有任何第三方日志框架,我们使用的就是jdk自带的
JUL
导入
commons-logging
并添加log4j依赖
和log4j.properties
配置文件输出结果
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
#配置根节点logger
log4j.rootLogger=info,consolelog4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-10p] [%t] [%d{yyyy-MM-dd HH:mm:ss:SSS}] [%l] %m%n
3、 JCL原理
- 通过LogFactory
动态加载
Log实现类 - Jdk14Logger就是jdk自带JUL日志框架(因为JUL从jdk1.4开始提供)
- SimpleLog是日志门面JCL自带日志,功能简单一般不用
日志门面
创建公共接口org.apache.commons.logging.Log
- 日志实现类Logger实现接口Log,这样对外暴露的Log不变,只需要动态加载不同的Logger
- 如果只导入JCL门面,不导入其他日志实现,那么日志实现为jdk自带JUL
- 如果导入JCL门面,并导入log4j依赖,那么日志实现为log4j,log4j优先级最高
二、SLF4J
1、SLF4J简介
- 简单日志门面(Simple Logging Facade For Java)
SLF4J
主要是为了给Java日志访问提供一套标准、规范的API框架 - 主要意义在于
提供接口
,具体的实现可以交由其他日志框架,例如log4j和logback等 - slf4j自己也提供了功能较为简单的实现,但是一般很少用到
- SLF4J最重要的两个功能就是对于
日志框架的绑定
以及日志框架的桥接
2、快速入门
slf4j依赖
<!--slf4j 核心依赖-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version>
</dependency><!--slf4j 自带的简单日志实现 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.25</version>
</dependency>
slf4j-api
只提供api,具体日志实现由slf4j-simple
提供
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class SLF4JTest {@Testpublic void test01(){Logger logger = LoggerFactory.getLogger(SLF4JTest.class);logger.trace("trace信息");logger.debug("debug信息");logger.info("info信息");logger.warn("warn信息");logger.error("error信息");}
}
输出结果:
2.1、输出动态信息
- Logger方法:
public void info(String format, Object... arguments);
@Test
public void test02() {Logger logger = LoggerFactory.getLogger(SLF4JTest.class);String name = "zs";int age = 23;// logger.info("学生信息-姓名:"+name+";年龄:"+age); 字符串拼接,效率低// logger.info("学生信息-姓名:{},年龄:{}",new Object[]{name,age}); 老方式,代码冗余logger.info("学生信息-姓名:{},年龄:{}", name, age);// 新方式,简单
}
输出结果:
2.2、异常信息的处理
- Logger方法:
public void info(String msg, Throwable t);
@Test
public void test03() {Logger logger = LoggerFactory.getLogger(SLF4JTest.class);try {Class.forName("aaa");} catch (ClassNotFoundException e) {// 打印栈追踪信息// e.printStackTrace();logger.info("具体错误是:", e);}
}
输出结果:
3、绑定日志的实现
使用slf4j绑定日志的流程
- 添加slf4j-api的依赖
- 使用slf4j的API在项目中进行统一的日志记录
- 绑定具体的日志实现框架
- 绑定已经实现了slf4j的日志框架,直接添加对应依赖
- 绑定没有实现slf4j的日志框架,先添加日志的适配器,再添加实现类的依赖
- slf4j有且
仅有一个
日志实现框架的绑定(如果出现多个默认使用第一个依赖日志实现)
使用slf4j绑定日志的原理
public class StaticLoggerBinder implements LoggerFactoryBinder
- 这个类负责静态
org.slf4j.LoggerFactory
类与相应的日志实现ILoggerFactory
类绑定 - 只要有这个类就可以实现slf4j门面+对应日志实现,包名都是org.slf4j.impl
3.1、slf4j实现slf4j-simple和logback
slf4j-simple和logback都是slf4j门面出现后才有的日志实现,所以这两生来就有自己的StaticLoggerBinder类。
依赖
<!--slf4j 核心依赖-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version>
</dependency><!-- logback依赖 -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency><!--slf4j 自带的简单日志实现 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.25</version>
</dependency>
导包
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
- 如果有多个日志实现的话,会出红色警告,默认使用
先导入
的实现 - 无论使用slf4j自己的slf4j-simple还是logback,导包都不会变,都用的以上两个
@Test
public void test04(){Logger logger = LoggerFactory.getLogger(SLF4JTest.class);logger.trace("trace信息");logger.debug("debug信息");logger.info("info信息");logger.warn("warn信息");logger.error("error信息");
}
输出结果:
3.2、slf4j绑定适配器实现log4j
- 由于log4j是在
slf4j之前
出品的日志框架实现,所以并没有遵循slf4j的API规范 - 之前集成的logback,是
slf4j之后
出品的日志框架实现,就是按照slf4j的标准指定的API,所以我们导入依赖就能用 - 如果想要使用slf4j门面,需要绑定一个
适配器slf4j-log4j12
依赖
<!--slf4j 核心依赖-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.25</version>
</dependency><!--
导入log4j适配器依赖
slf4j-log4j12依赖的slf4j-api,slf4j-api可以不用重复导入依赖-->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.25</version>
</dependency>
导包
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Test
public void test05(){Logger logger = LoggerFactory.getLogger(SLF4JTest.class);logger.trace("trace信息");logger.debug("debug信息");logger.info("info信息");logger.warn("warn信息");logger.error("error信息");
}
log4j.properties
#指定日志的输出级别与输出端
log4j.rootLogger=info,console# 配置appender输出方式:输出到控制台
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-10p] [%t] [%d{yyyy-MM-dd HH:mm:ss:SSS}] [%l] %m%n
输出结果:
与slf4j-simple和logback的实现原理其实一样,都是在相同包下org.slf4j.impl
下创建StaticLoggerBinder
类将slf4j门面与日志实现绑定
起来。log4j需要适配器slf4j-log4j12
,JUL需要适配器slf4j-jdk14
4、桥接旧的日志框架
桥接解决的问题:当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现
- 先去除之前老的日志框架的依赖
- 添加SLF4J提供的桥接组件
- 为项目添加SLF4J的具体实现
4.1、log4j日志重构为slf4j+logback的组合
重构前
依赖
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
log4j.properties
#配置根节点logger
log4j.rootLogger=trace,consolelog4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern=[%-10p]%r %c%t%d{yyyy-MM-dd HH:mm:ss:SSS} %m%n
导包
import org.apache.log4j.Logger;
@Test
public void test07(){Logger logger = Logger.getLogger(Log4jTest.class);logger.info("info信息");
}
- 查看Logger类源码,属于
log4j包下
的类
重构后
- 依赖:删除log4j依赖,添加slf4j提供的桥接组件和logback依赖
<!-- log4j相关的桥接器 -->
<dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId><version>1.7.25</version>
</dependency>
<!-- logback依赖 -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>
- 导包:依然不变
import org.apache.log4j.Logger;
@Test
public void test08(){Logger logger = Logger.getLogger(Log4jTest.class);logger.info("info信息");
}
- 查看Logger类源码,属于
log4j-over-slf4j包下
的类
如此操作,看上去依赖还是org.apache.log4j.Logger,实际已不再是log4j包下的类,日志实现也变成了slf4j门面可以随意搭配的方式了。
相关文章:

java日志门面之JCL和SLF4J
文章目录 前言一、JCL1、JCL简介2、快速入门3、 JCL原理 二、SLF4J1、SLF4J简介2、快速入门2.1、输出动态信息2.2、异常信息的处理 3、绑定日志的实现3.1、slf4j实现slf4j-simple和logback3.2、slf4j绑定适配器实现log4j 4、桥接旧的日志框架4.1、log4j日志重构为slf4jlogback的…...

Oracle DB运维常用的视图及数据字典
List item 本文介绍一些Oracle DB日常运维最常用到(使用频率很高)的视图及数据字典 用户有关的常用视图: 1、 查看当前用户的缺省表空间* SQL>select username,default_tablespace from user_users; 2、 查看当前用户的角色 SQL>sele…...

vue.config.js devServer中changeOrigin的作用
问题 vue开发时,为了解决前端跨域问题,通常在vue.config.js配置 devServer proxy devServer: {proxy:{/api: {target: http://b.com,changeOrigin: false},}, }官方文档http-proxy options对changeOrigin的解释 option.changeOrigin: true/false, Defa…...

基于Ubuntu 20.04 LTS上部署MicroK8s(最小生产的 Kubernetes)
目录 文章目录 目录简介Kubernetes简介MicroK8s简介Ubuntu系统MicroK8s的优势安装环境基本要求执行安装命令加入群组(使用非 root 用户访问)开启 dashboard 仪表盘查看服务名称查看仪表盘开放的端口打开浏览器检查状态打开你想要的服务(使用附加组件)开始使用 microk8s访问 Kub…...

Spring:项目中的统一异常处理和自定义异常
介绍异常的处理方式。在项目中,都会进行自定义异常,并且都是需要配合统一结果返回进行使用。 1.背景引入 (1)背景介绍 为什么要处理异常?如果不处理项目中的异常信息,前端访问我们后端就是显示访问失败的…...

有点快要跟不上时代的感觉
团队的群里面有一个同事突然问了下,下面的这个 JavaScript 如何进行优化 var startIndex (start undefined || start null) ? null : start[0].Value;看上面的代码就是典型的判断和返回的问题。 如果是要调试的话也不是做不出来,但可能要花点时间&a…...

【pytorch】pytorch入门4:神经网络的卷积层
文章目录 前言一、定义概念 缩写二、性质三、代码总结参考文献 前言 使用 B站小土堆课程的笔记 一、定义概念 缩写 卷积层是神经网络中用于突出特征来进行分类任务的层。 二、性质 卷积核例子:vgg16 model 三、代码 添加库 python代码块import os import …...

【机器学习】探索LSTM:深度学习领域的强大时间序列处理能力
目录 🍔 LSTM介绍 🍔 LSTM的内部结构图 2.1 LSTM结构分析 2.2 Bi-LSTM介绍 2.3 使用Pytorch构建LSTM模型 2.4 LSTM优缺点 🍔 小结 学习目标 🍀 了解LSTM内部结构及计算公式. 🍀 掌握Pytorch中LSTM工具的使用. &…...

QT学习笔记之文件操作
你千万不要跟任何人谈起任何事。你只要一谈起,就会想念起每一个人来。 在ui界面添加一个LineEdit(lEt)、QPushButton(btn)、QWidget widget.cpp #include "widget.h" #include "ui_widget.h" #include <QFile> #include <QFileDialo…...

Mybatis XML配置文件操作数据库
Mybaits在操作数据库时,可以有两种方式;第一种是使用注解的方式操作,另一种是使用XML配置文件的方式:一般而言,若没有特别的要求,则编写一些简单的SQL语句,可以直接使用注解的方式;编…...

Ansible-template模块动态生成特定文件
文章目录 一、Jinja2介绍什么是主要特性安装基本用法进阶特性总结 Jinja2与Ansible关系1. 模板引擎2. Ansible 的依赖3. 变量和模板4. 动态生成配置5. 社区和生态系统总结 二、Ansible如何使用Jinja2使用template模块Jinja2文件中使用判断和循环Jinja2文件中使用判断语法 Jinja…...

【Hadoop】【vim编辑器】【~/.bashrc 文件】如何编辑
1. 进入 vim 编辑器 在终端中输入以下命令: vim ~/.bashrc 2. 进入插入模式 打开文件后,你将处于普通模式。在普通模式下,你不能直接编辑文本。 要进入插入模式,请按下 i 键。这时,你应该会看到屏幕底部出现 -- 插…...

vs code自动报错
让vs code自动报错, 点击插件 → 搜索error lens → 点击install, 下载完后,编写的代码有问题就会自动报错了。 5、修改默认缩进字符 点击设置(settings) → 点击常用设置 → 修改字符缩进。...

详细分析Nginx中的proxy_pass 末尾斜杠
目录 前言1. 基本知识2. Demo 前言 对于Nginx的讲解,更多推荐阅读: Nginx配置静态网页访问(图文界面)Nginx将https重定向为http进行访问的配置(附Demo)Nginx从入门到精通(全)详细分…...

数据结构:双指针—移动0(OJ283)
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]示例 2: 输入: nums [0] 输出: […...

LeetCode - 850 矩形面积 II
题目来源 850. 矩形面积 II - 力扣(LeetCode) 题目描述 给你一个轴对齐的二维数组 rectangles 。 对于 rectangle[i] [x1, y1, x2, y2],其中(x1,y1)是矩形 i 左下角的坐标, (xi1, yi1) 是该…...

Jenkins Pipeline 中通过勾选参数来控制是否构建 Docker 镜像
1.定义参数: 使用 booleanParam 定义一个布尔参数,示例如下 booleanParam(name: BUILD_DOCKER, description: 是否构建Docker镜像, defaultValue: false)2.使用参数: 在 stage 中,根据参数的值决定构建方式: stage(编…...

C++入门基础知识86(实例)——实例11【计算自然数之和】
成长路上不孤单😊😊😊😊😊😊 【14后😊///C爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于计算自然数之和相关内容! 关…...

ChatGPT与R语言融合技术在生态环境数据统计分析、绘图、模型中的实践与进阶应用
自2022年GPT(Generative Pre-trained Transformer)大语言模型的发布以来,它以其卓越的自然语言处理能力和广泛的应用潜力,在学术界和工业界掀起了一场革命。在短短一年多的时间里,GPT已经在多个领域展现出其独特的价值…...

OpenAi以及Dify结合生成Ai模型
文章目录 1、Dify介绍2、使用 Dify3、部署Docker1.系统要求2.系统虚拟化3.下载docker 4、安装WSL1.检查是否已经安装 五、访问系统六、添加模型 1、Dify介绍 Dify官方地址。 Dify 是一个开源的 LLM 应用开发平台。其直观的界面结合了 AI 工作流、RAG 管道、Agent、模型管理、…...

【漏洞复现】用友 UFIDA /portal/pt/file/upload 任意文件上传漏洞
免责声明: 本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测试时,可能会违反某些法律法规或服…...

C:内存函数
目录 前言: 一、memcpy 函数的使用及实现 1、memcpy函数的介绍 1.1 memcpy函数参数解读 2、memcpy函数的使用 3、memcpy函数的模拟实现 二、memmove函数的使用及模拟 1、memmove函数的使用 2、memmove函数的模拟实现 三、memset 函数的使用 1、memset函数的…...

【Web】御网杯信息安全大赛2024 wp(全)
目录 input_data admin flask 如此多的FLAG 一夜醒来之全国CTF水平提升1000倍😋 input_data 访问./.svn后随便翻一翻拿到flag admin dirsearch扫出来 访问./error看出来是java框架 测出来是/admin;/路由打Spring View Manipulation(Java)的SSTI https:/…...

VC++同时处理ANSI和Unicode字符集,除了使用TCHAR和_T()宏外,还有其他方法可以实现吗?
在我的C项目中,如果我需要同时处理ANSI和Unicode字符集,除了使用TCHAR和_T()宏外,还有其他方法可以实现吗? 除了使用 TCHAR 和 _T() 宏之外,还有其他方法可以实现同时处理 ANSI 和 Unicode 字符集: 1. 使用…...

MATLAB定位程序与讲解【专栏介绍】
AOA(到达角度)定位原理: 描述了基于到达角度进行定位的方法,适用于一维、二维或三维空间。 由动静压之比求马赫数的MATLAB函数: 提供了一个计算马赫数的函数,用于流体力学中速度的计算。 三边法定位与三点法…...

机器学习3--numpy
Numpy 一、numpy是什么?二、N维数组三、数组基本操作四、数组的运算 一、numpy是什么? numpy是一个开源的python科学计算库,用于处理任意维度的数组。numpy用ndarray处理多维数组。 import numpy as np np.array创建数组 机器学习数据量很大…...

Linux之我不会
一、常用命令 1.系统管理 1.1 systemctl start | stop | restart | status 服务名 案例实操 1 查看防火墙状态 systemctl status firewalld2 停止防火墙服务 systemctl stop firewalld3 启动防火墙服务 systemctl start firewalld4 重启防火墙服务 systemctl restart f…...

音视频整体解码流程和同步流程
目录 1. 整体解码流程1. 初始化 FFmpeg2. 打开媒体文件3. 查找解码器4. 打开解码器5. 读取和解码数据6. 处理解码后的帧7. 释放资源 2. 音视频同步整体流程1. 解复用媒体流2. 解码3. 以音频为时钟源进行音视频同步的策略4. 缓冲区设计 现在先说大体流程,不分析代码 …...

1.2 HuggingFists安装说明-Linux安装
Linux版安装说明 下载地址 【GitHub】https://github.com/Datayoo/HuggingFists 【百度网盘】https://pan.baidu.com/s/12-qzxARjzRjYFvF8ddUJQQ?pwd2024 安装说明 环境要求 操作系统:CentOS7 硬件环境:至少4核8G,系统使用Containerd…...

四,MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用)
四,MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用) 文章目录 四,MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用)1. 主键策略1.1 主键生成策略介绍 2. 准备工作:2.1 AUTO 策略2.2 INPUT 策略2.3 ASSIGN_ID 策略2.3.1 雪花算…...