Java日志门面- JCL和 常用日志门面SLFJ详解

使用日志门面的原因

目前经常用的日志框架技术有:JUL、Log4j、log4j2、logback用来记录日志信息 ,之前我们讲过,我们学习不同的日志框架。他们的API是不同的,这样难以进行有效的记忆,同时在我们的生产环境下,如果我们已经选择使用了一款日志框架,但根据需求的改变而选择使用了另一种.那么我们用来操作日志的源码都需要发生变化,因此,此时需要一写接口,我们只需要在源码中调用调用接口,接口去调用需要的日志框架。这些接口就是我们说是日志门面。

日志门面介绍

为了将各个服务框架中自带的日志进行统一门面处理,使用门面技术。

常用日志门面技术:JCL、slf4j,用来解决 应用程序 在使用各种日志框架对应API时候导致的耦合性,因此提出一套门面技术,开发人员只需调用门面接口即可。


日志门面技术的好处

       门面技术是面向接口的开发,不再依赖具体的实现类,减少代码的耦合性可以根据实际需求,灵活的切换日志框架,统一的API,方便开发者学习和使用,统一的配置管理便于项目日志的维护工作。


JCL

1、JCL简介

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

JCL有两个基本的抽象类:

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

Log 的继承体系与 LogFactory 的继承体系

2、入门案例

1、创建测试类,如下:

public class JCLTest {
    @Test
    public void test() {
        Log log = LogFactory.getLog(JCLTest.class);

        //日志级别
        log.fatal("fatal");//严重错误,一般会造成系统崩溃并终止运行
        log.error("error"); // 错误信息,不会影响系统运行

        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
    }
}

 2、在pom文件中添加依赖,在不依赖 log4j 实现类框架情况下,如下:

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

3、在不依赖 log4j 实现类框架情况下,运行结果如下:

 注意:JCL是一个日志门面类API,内设各种接口,但在没有依赖日志实现框架的情况下,自身带有一个SimpleLog实现类,但功能较弱,因此一般不用。

 4、在pom文件中添加依赖,在 依赖 log4j 实现类框架情况下如下:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

5、不创建log4j.properties配置文件,运行结果如下:

说明JCL在有依赖日志实现的框架情况下,会自动依赖日志框架,具体实现流程如下:

  • 执行 Log log = LogFactory.getLog(Log4jTest.class);
  • 进入 getFactory().getInstance(clazz)方法;
  • 进入 instance = newInstance(name);方法;
  • 进入 LogFactoryImp类中的discoverLogImplementation(name)方法;
  • 执行 createLogFromClass(classesToDiscover[i], logCategory, true);
  • classesToDiscover的值如图所示:

 

      过程就是JCL运行时动态查找具体日志框架,依次去判断类路径中是否存在Log4J、JDK14、jdk13、Simplelog依赖。加载顺序首先加载的就是Log4J,如果不存在则继续加载其他。

     通过源码 及 Log 的继承体系与 LogFactory 的继承体系我们发现,Log接口的4个实现类

  • Log4jLogger: 我们集成的log4j
  • JDK14Logger: JDK自带JUL(java.util.logging)
  • JDk13Logger: JDK自带JUL(java.util.logging),JDK14之前的版本使用
  • SimpleLogger: JCL自带实现类

3、JCL案例完整代码

1、在pom文件中添加依赖,如下:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

2、创建测试类,如下:

public class JCLTest {
    @Test
    public void test() {
        Log log = LogFactory.getLog(JCLTest.class);

        //日志级别
        log.fatal("fatal");//严重错误,一般会造成系统崩溃并终止运行
        log.error("error"); // 错误信息,不会影响系统运行

        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
    }
}

3、在resources目录下创建 log4j.propertites配置文件,如下:

# 配置 Root 顶级父元素
# 指定日志输出级别为=debug ,使用的appender为=console、file、dailyFile,rollingFile

#  注意:appender选项console、file、dailyFile,rollingFile,使用哪个,选择哪个
  log4j.rootLogger = debug,console

# 指定 控制台日志
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定 消息格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定 消息格式的内容  %p:消息级别、%r:消息用的时间、
# %c:类全名、%t:线程名、%F:文件名 %L:行号
# [%p]%r %c %t %F %L %d{yyyy-MM-dd HH:mm:ss} = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss}
log4j.appender.console.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n


# 指定 日志输出到文件
# 指定 日志输出到数据库Mysql

# 按照时间输出日志
# 按照日志大小拆分输出日志

以上四个appender可以参考:Java的常用日志技术详解_爱吃面的猫的博客-CSDN博客

4、测试结果如下:


SLF4J

1、SLF4J简介

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

2、入门案例

01、在pom文件中添加slf4j依赖和slf4j自带的简单日志实现包,依赖添加如下:

<dependencies>
    <!--  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>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.17</version>
    </dependency>
</dependencies>

02、创建测试类,代码如下:

public class SLF4JTest {
    @Test
    public void test() {
        Logger log = LoggerFactory.getLogger(SLF4JTest.class);

        //日志级别:默认打印级别是info,所以打印info级别及一下级别信息
        log.error("error"); // 错误信息,不会影响系统运行
        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
    }
}

03、在没有任何其他日志实现框架集成的基础之上,slf4j使用的就是自带的框架slf4j-simple,但slf4j-simple也必须以单独依赖的形式导入进来,运行结果如下:

3、集成日志实现框架的方式

3.1 日志时间线

日志出现的时间顺序,即日志时间线

  • 常见的日志实现:JUL、log4j、logback、log4j2
  • 常见的日志门面:JCL、slf4j
  • 时间线: log4j --> JUL --> JCL --> slf4j --> logback --> log4j2

3.2 日志实现集成

查看SLF4J日志官网的用户手册,观察日志实现的方式,如下图:

通过上图发现,slf4j集成日志框架的有以下几种方式:

集成日志实现框架

描述

导入依赖

/dev/null

没有集成任何日志框架,日志是不能够绑定实现任何功能的

slf4j核心依赖是不提供任何实现的。

<!--  slf4j核心依赖   -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>

slf4j-simple

是slf4j时间线后提供的日志实现

的API完全遵循slf4j进行的设计

是slf4j-simple是slf4j官方提供

与slf4j无缝衔接,导入依赖,自动绑定到slf4j门面上,无需适配器

<!--  slf4j 自带的日志简单实现   -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.25</version>
</dependency>

Logback

slf4j门面时间线后面提供的日志实现

API完全遵循slf4j进行的设计

与slf4j无缝衔接,导入依赖,自动绑定到slf4j门面上,无需适配器

<!--  slf4j 集成 logback,logback在slf4j时间线后出现,API遵循slf4j设计,无缝连接   -->
<!--  依赖具有传递性 ,logback导入 logback-classic 即可   -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

Nop

slf4j门面时间线后面提供的日志实现

API完全遵循slf4j进行的设计

与slf4j无缝衔接,导入依赖,自动绑定到slf4j门面上,无需适配器

虽然也划分到实现中,但它是指不实现日志记录

<!--  slf4j 的不记录日志,即禁止日志打印   -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.7.25</version>
</dependency>

log4j

slf4j时间线前的日志实现

API不遵循slf4j进行的设计,

通过适配桥接技术与slf4j衔接

适配器是slf4j-log4j12

<!--  导入 log4j 适配器  -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
</dependency>
<!--  slf4j 集成 log4j  -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

JUL

slf4j时间线前的日志实现

API不遵循slf4j进行的设计,

通过适配桥接技术与slf4j衔接

适配器是slf4j-jdk14

<!--  导入 JUL 适配器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.32</version>
</dependency>

4、集成 log4j 案例

1、导入 log4j 适配器、 slf4j 依赖和 log4j 依赖 
因为log4j和JUL是在slf4j时间线之前,log4j和JUL的API不遵循slf4j设计,所以 slf4j集成log4j和JUL需要适配器,在pom文件中导入 log4j 适配器:

<dependencies>
    <!--  slf4j核心依赖   -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>  
    <!--  导入 log4j 适配器  -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
    <!--  slf4j 集成 log4j  -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.17</version>
    </dependency>
</dependencies>

2、配置 log4j.properties
为了测试方式,只配置控制台的appender,FileAppender及其他appender根据需要自行配置。

# 配置 Root 顶级父元素
# 指定日志输出级别为=debug ,使用的appender为=console、file、
log4j.rootLogger = debug,console

# 指定 控制台日志
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 指定 消息格式
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 指定 消息格式的内容 
log4j.appender.console.layout.conversionPattern = [%p]%r %l %d{yyyy-MM-dd HH:mm:ss} %m%n

3、创建测试类

public class SLF4JTest {
    @Test
    public void test() {
        Logger log = LoggerFactory.getLogger(SLF4JTest.class);

        //日志级别:默认打印级别是info,所以打印info级别及一下级别信息
        log.error("error"); // 错误信息,不会影响系统运行
        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
        try {
            Class.forName("aaa");
        } catch (ClassNotFoundException e) {
            log.info("类中出现错误信息",e);
        }
    }
}

4、运行测试类,结果如下: 

5、集成 logback 案例

1、导入 logback 依赖

因为 logback 是在 slf4j 时间线之后出现,所以logback的API完全遵循 slf4j 进行设计,并且会与 slf4j 无缝连接,导入依赖会自动绑定到 slf4j 上面。

<dependencies>
   <!--  slf4j核心依赖   -->
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <version>1.7.25</version>
   </dependency>
   
   <!--  slf4j 集成 logback,logback在slf4j时间线后出现,API遵循slf4j设计,无缝连接   -->
   <!--  依赖具有传递性 ,logback导入 logback-classic 即可   -->
   <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
       <version>1.2.11</version>
   </dependency>
   
   <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.12</version>
   </dependency>

</dependencies>

2、创建测试类,如果需要配置文件,则是logback.xml格式

public class SLF4JTest {
    @Test
    public void test() {
        Logger log = LoggerFactory.getLogger(SLF4JTest.class);

        //日志级别:默认打印级别是info,所以打印info级别及一下级别信息
        log.error("error"); // 错误信息,不会影响系统运行
        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
        try {
            Class.forName("aaa");
        } catch (ClassNotFoundException e) {
            log.info("类中出现错误信息",e);
        }
    }
}

3、运行测试类,测试结果如下

6、集成 nop 案例(了解)

禁止日志记录,即禁止日志打印。

 1、导入 nop 依赖

<dependencies>
   <!--  slf4j核心依赖   -->
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <version>1.7.25</version>
   </dependency>
   
   <!--  slf4j 的不记录日志,即禁止日志打印   -->
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-nop</artifactId>
       <version>1.7.25</version>
   </dependency>
   
   <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.12</version>
   </dependency>

</dependencies>

2、创建测试类,如果需要配置文件,则是logback.xml格式

public class SLF4JTest {
    @Test
    public void test() {
        Logger log = LoggerFactory.getLogger(SLF4JTest.class);

        //日志级别:默认打印级别是info,所以打印info级别及一下级别信息
        log.error("error"); // 错误信息,不会影响系统运行
        log.warn("warn");//警告信息,可能会发生问题
        log.info("info");// 运行信息,数据连接、网络连接、I0操作等等
        log.debug("debug");// 调试信息,一般在开发中使用,记录程序变量参数传递信息等等
        log.trace("trace"); //追踪信息,记录程序所有的流程信息
        try {
            Class.forName("aaa");
        } catch (ClassNotFoundException e) {
            log.info("类中出现错误信息",e);
        }
    }
}

3、运行测试类,测试结果如下

注意:依赖多个日志实现类,则默认按先导入的依赖的作为slf4j日志实现。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值