适配器模式在 Java 日志中的应用
Java 中有很多日志框架,在项目开发中,我们常常用它们来打印日志信息。其中,比较常用的有 log4j、logback,以及 JDK 提供的 JUL(java.util.logging) 和 Apache 的 JCL(Jakarta Commons Logging) 等。
大部分日志框架都提供了相似的功能,比如按照不同级别(debug、info、warn、erro……)打印日志等,但它们却并没有实现统一的接口
。这主要可能是历史的原因,它不像 JDBC 那样,一开始就制定了数据库操作的接口规范。
如果我们只是开发一个自己用的项目,那用什么日志框架都可以,log4j、logback 随便选一个就好。但是,如果我们开发的是一个集成到其他系统的组件、框架、类库等,那日志框架的选择就没那么随意了
。
比如,项目中用到的某个组件使用 log4j 来打印日志,而我们项目本身使用的是 logback。将组件引入到项目之后,我们的项目就相当于有了两套日志打印框架。每种日志框架都有自己特有的配置方式。所以,我们要针对每种日志框架编写不同的配置文件(比如,日志存储的文件地址、打印日志的格式)。如果引入多个组件,每个组件使用的日志框架都不一样,那日志本身的管理工作就变得非常复杂。
所以,为了解决这个问题,我们需要统一日志打印框架。
如果你是做 Java 开发的,那 Slf4j 这个日志框架你肯定不陌生,它相当于 JDBC 规范,提供了一套打印日志的统一接口规范。不过,它只定义了接口,并没有提供具体的实现,需要配合其他日志框架(log4j、logback……)来使用
不仅如此,Slf4j 的出现晚于 JUL、JCL、log4j 等日志框架,所以,这些日志框架也不可能牺牲掉版本兼容性,将接口改造成符合 Slf4j 接口规范。Slf4j 也事先考虑到了这个问题,所以,它不仅仅提供了统一的接口定义,还提供了针对不同日志框架的适配器
。对不同日志框架的接口进行二次封装,适配成统一的 Slf4j 接口定义。具体的代码示例如下所示:
// slf4j统一的接口定义
package org.slf4j;
public interface Logger {public boolean isTraceEnabled();public void trace(String msg);public void trace(String format, Object arg);public void trace(String format, Object arg1, Object arg2);public void trace(String format, Object[] argArray);public void trace(String msg, Throwable t);public boolean isDebugEnabled();public void debug(String msg);public void debug(String format, Object arg);public void debug(String format, Object arg1, Object arg2)public void debug(String format, Object[] argArray)public void debug(String msg, Throwable t);//...省略info、warn、error等一堆接口
}// log4j日志框架的适配器
// Log4jLoggerAdapter实现了LocationAwareLogger接口,
// 其中LocationAwareLogger继承自Logger接口,
// 也就相当于Log4jLoggerAdapter实现了Logger接口。
package org.slf4j.impl;
public final class Log4jLoggerAdapter extends MarkerIgnoringBaseimplements LocationAwareLogger, Serializable {final transient org.apache.log4j.Logger logger; // log4jpublic boolean isDebugEnabled() {return logger.isDebugEnabled();}public void debug(String msg) {logger.log(FQCN, Level.DEBUG, msg, null);}public void debug(String format, Object arg) {if (logger.isDebugEnabled()) {FormattingTuple ft = MessageFormatter.format(format, arg);logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());}}public void debug(String format, Object arg1, Object arg2) {if (logger.isDebugEnabled()) {FormattingTuple ft = MessageFormatter.format(format, arg1, arg2);logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());}}public void debug(String format, Object[] argArray) {if (logger.isDebugEnabled()) {FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());}}public void debug(String msg, Throwable t) {logger.log(FQCN, Level.DEBUG, msg, t);}//...省略一堆接口的实现...
}
所以,在开发业务系统或者开发框架、组件的时候,我们统一使用 Slf4j 提供的接口来编写打印日志的代码
,具体使用哪种日志框架实现(log4j、logback……),是可以动态地指定的(使用 Java 的 SPI 技术,这里我不多解释,你自行研究吧),只需要将相应的 SDK 导入到项目中即可。
不过,你可能会说,如果一些老的项目没有使用 Slf4j,而是直接使用比如 JCL 来打印日志,那如果想要替换成其他日志框架,比如 log4j,该怎么办呢?实际上,Slf4j 不仅仅提供了从其他日志框架到 Slf4j 的适配器,还提供了反向适配器,也就是从 Slf4j 到其他日志框架的适配
。我们可以先将 JCL 切换为 Slf4j,然后再将 Slf4j 切换为 log4j。经过两次适配器的转换,我们就能成功将 log4j 切换为了 logback。
总结
- 适配器模式用于提高兼容性
思考
适配器有两种实现方式:类适配器、对象适配器。那我们之前讲到的代理模式、装饰器模式,是否也同样可以有两种实现方式(类代理模式、对象代理模式,以及类装饰器模式、对象装饰器模式)呢?
参考
51 | 适配器模式:代理、适配器、桥接、装饰,这四个模式有何区别?
适配器模式在 Java 日志中的应用相关推荐
- java中文变成问号怎么解码_alpine 镜像 java 日志中文问号乱码
0x00 前言 吾使用 alpine 作为基础镜像构建了 jdk8 镜像,为线上业务的 java 微服务架构提供支持,但是有容器运行的 java 服务中打印的日志中一旦出现中文,就会出现诸如以下的 ? ...
- 探索java世界中的日志奥秘
java日志简单介绍 对于一个应用程序来说日志记录是必不可少的一部分.线上问题追踪,基于日志的业务逻辑统计分析等都离不日志.JAVA领域存在多种日志框架,目前常用的日志框架包括Log4j,Log4j ...
- Java中的记录器 - Java日志示例
Java中的记录器 - Java日志示例 今天我们将研究Java中的Logger.Java Logger提供了java编程的日志记录. 目录[ 隐藏 ] 1 Java中的记录器 1.1 Java Lo ...
- java日志怎么实现_JAVA项目中怎么实现一个通用日志记录功能
JAVA项目中怎么实现一个通用日志记录功能 发布时间:2020-11-21 17:04:50 来源:亿速云 阅读:53 作者:Leah 今天就跟大家聊聊有关JAVA项目中怎么实现一个通用日志记录功能, ...
- 获取日志的等级_进阶之路:Java 日志框架全画传(中)
导读:随着互联网和大数据的蓬勃发展,分布式日志系统以及日志分析系统得到了广泛地应用.目前,几乎在所有应用程序中,都会用到各种各样的日志框架来记录程序的运行信息.鉴于此,工程师十分有必要熟悉主流的日志记 ...
- Java项目中这样打印错误日志,排查问题更高效
在程序中打错误日志的主要目标是为更好地排查问题和解决问题提供重要线索和指导.但是在实际中打的错误日志内容和格式变化多样,错误提示上可能残缺不全.没有相关背景.不明其义,使得排查解决问题成为非常不方便或 ...
- 在Java项目中打印错误日志的正确姿势,排查问题更方便,非常实用!
作者:琴水玉 cnblogs.com/lovesqcc/p/4319594.html 在程序中打错误日志的主要目标是为更好地排查问题和解决问题提供重要线索和指导.但是在实际中打的错误日志内容和格式变化 ...
- 请不要在Java项目中乱打印日志了,这才是正确姿势,非常实用!
点击上方"码农突围",马上关注 这里是码农充电第一站,回复"666",获取一份专属大礼包 真爱,请设置"星标"或点个"在看&quo ...
- error 系统错误 错误码10007_在Java项目中打印错误日志的正确姿势,排查问题更方便,非常实用!...
作者:琴水玉 cnblogs.com/lovesqcc/p/4319594.html 在程序中打错误日志的主要目标是为更好地排查问题和解决问题提供重要线索和指导. 但是在实际中打的错误日志内容和格式变 ...
最新文章
- WinCE5.0移动平台开发笔记(c#中使用多线程访问winform中控件的若干问题(zt))
- python dlib 的安装
- mysql删除有空格字符名称的触发器
- 为博客园添加github跳转链接
- int ,long , long long类型的范围
- Spring Cloud【Finchley】实战-07异步下单
- 《AutoCAD全套园林图纸绘制自学手册》一第1章 园林设计基本概念1.1 概述
- 第一行代码学习笔记第二章——探究活动
- 从动力学角度看优化算法SGD:一些小启示
- 20世纪物理学巨人、诺奖得主菲利普安德森逝世,享年96岁
- MySQL 事务的面试题总结
- Java语言程序设计(一)选择题
- 自己总结一下wpf image source 绑定的几种方式
- IDC销售系统前台模板知了云模板
- bzoj3654 图样图森破
- 看京东和淘宝的地址薄设计----填写订单的场景下
- pytorch distiller Weights Pruning Algorithms
- 在style中设置图片背景
- 氚云徐平俊:低代码赛道热度陡升,今年增长目标200%
- finalshell - 新建并连接服务
热门文章
- linux中查看网卡型号的命令
- ubuntu 安装 virt-manager 虚拟机
- 人生的四大天规,越早明白,越有福气
- 研究生不知道怎么看论文?赶紧把学长的经验码起来
- redis php高级使用_项目中应用Redis+Php的场景
- SpringBoot 中 @Transactional 的使用
- qt及qt quick开发实战精解_Qt5实战001:Qt 5.15下载安装详解
- 水晶报表中对某一栏位值进行处理_从主流报表工具的报价看报表行业的报价水深-----常用报表工具对比---主流报表价格对比...
- contos7改分辨率_centos7分辨率怎么设置-修改centos7分辨率的方法 - 河东软件园
- java过滤html相关标签