JAVA日志slf4j 的大一统

259 阅读2分钟

一、常见的日志框架

具体日志实现框架:

  • Log4j
  • log4j2
  • logback
  • jul (java.util.logging)
  • simpleLog
  • 其他 日志门面(抽象):
  • jcl (commons-logging)
  • slf4j (Simple Logging Facade for JAVA)
  • log4j2 也支持门面模式

目前市面比较流行的主要是log4j2 和logback、slf4j了

常用的搭配有:

  1. commons-logging + log4j 这种基本已经被淘汰
  2. slf4j + logback 目前的主流
  3. log4j-api + log4j-core
  4. slf4j + log4j-core

二、JCL 的介绍

maven 引入

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

用法:

public void jcl(){
Log logger = LogFactory.getLog("jcl");
logger.info("jcl");
}

核心代码: 目前JCL 内置的4中日志。

private static final String[] classesToDiscover = {
     LOGGING_IMPL_LOG4J_LOGGER,
     "org.apache.commons.logging.impl.Jdk14Logger",
     "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
     "org.apache.commons.logging.impl.SimpleLog"
};

JCL全称jarkartConnons-logging 可以统一编程,因为他是抽象的,可以根据用户提供的具体日志技术去实例化具体的对象,所以一定程度上可以解决不同日志的问题;JCL的原理是内置了一个字符串数组,这个数组当中保存了类名; 在调用getLogger方法去实例化一个logger对象的时候会遍历这个数组,从这个数组当中拿到类目如果 能够通过class.forName加载到说明用户配置了该日志技术,从而使用该日志技术。

缺点: 内置的数组属于硬编码、并且数量有限只能解决小部分日志问题、无法解决在使用JCL之前遗留 的问题;最大的问题是他没有更新了

目前已基本废弃。 JCL 原理图

image.png

三、slf4j 介绍

SLF4J全称 Simple Logging Facade for JAVA ,是通过绑定器来和具体日志框架工作的。 maven 引入:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.32</version>
</dependency>

示例代码:

public void slf4j(){
  Logger logger = LoggerFactory.getLogger("slf4j");
  logger.error("slf4j");
}

下面重点介绍下 SLF4J 的工作原理,如图:

image.png

官网扒下来的图 (www.slf4j.org/manual.html…

image.png

优点: 统一编程方式,假如有新的日志框架出现可以发布新的绑定器来实现拓展,也就是增加新的绑定器jar包即可,程序员引入新的绑定器jar即可实现转换。

缺点:无法解决历史硬编码问题

硬编码问题?什么是硬编码问题?怎么解决硬编码的问题呢 ?
例如 这种直接使用 log4j 的打印,没有使用任何日志门脸框架

import org.apache.log4j.Logger;
/**
 * @Author
 * @Date 2022/1/6 11:29
 */
public class MyApp {
    static Logger logger = Logger.getLogger(MyApp.class);
    public static void main(String[] args) {
        logger.info("这是org.apache.log4j.Logger 日志打印");
    }
}

那slf4j 是怎么解决这种硬编码问题的呢?
slf4j 引入一个新的概念 -- 桥接器
桥接器工作原理:

image.png

相关依赖坐标解释

<!-- log4j1 核心-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency> 
<!-- jcl 核心-->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<!-- logback-绑定器 包含了核心和slf4j 以及logback的绑定器 三个 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.4</version>
</dependency>
<!-- slf4j-api 核心-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.32</version>
</dependency>
<!-- slf4j-log4j1 绑定器-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.32</version>
</dependency> 
<!-- log4j2-slf4j-impl 绑定器 绑定log4j2 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>2.13.3</version>
</dependency>
<!-- log4j2桥接器-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-to-slf4j</artifactId>
    <version>2.9.1</version>
</dependency>
<!-- log4j-over-slf4j log4j1的桥接器 不能和log4j1的核心共存会有jar冲突问题 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.32</version>
</dependency>
<!-- log4j2 核心-->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.13.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.13.2</version>
</dependency>

四、 总结

1.slf4j 已成主流,一统天下
2.兼容硬编码是它优于其他框架的显著优势。