zoukankan      html  css  js  c++  java
  • 005-log-slf4j

    一、概述

         SLF4J = Simple Logging Facade for Java.
         author: Ceki Gülcü
         SLF4J,即简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,而是通过Facade Pattern提供一些Java logging API,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。作者创建SLF4J的目的是为了替代Jakarta Commons-Logging。

    1.1、POM依赖

    基础门面

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

    桥接包

    slfj-log4j12.jar (表示桥接 log4j)
    slf4j-jdk14.jar(表示桥接jdk Looging)
    sIf4j-jcl.jar(表示桥接 jcl)
    log4j-slf4j-impl(表示桥接log4j2)
    logback-classic(表示桥接 logback)

    1.2、java代码

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    //省略
    Logger logger = LoggerFactory.getLogger(Test.class);
    // 省略
    logger.info("info");

    在代码中,并不会出现具体日志框架的api。程序根据classpath中的桥接器类型,和日志框架类型,判断出logger.info应该以什么框架输出!注意了,如果classpath中不小心引了两个桥接器,那会直接报错的!

    二、详解  

         实际上,SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类。在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。SLF4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。
         那么什么时候使用SLF4J比较合适呢?
         如果你开发的是类库或者嵌入式组件,那么就应该考虑采用SLF4J,因为不可能影响最终用户选择哪种日志系统。在另一方面,如果是一个简单或者独立的应用,确定只有一种日志系统,那么就没有使用SLF4J的必要。假设你打算将你使用log4j的产品卖给要求使用JDK 1.4 Logging的用户时,面对成千上万的log4j调用的修改,相信这绝对不是一件轻松的事情。但是如果开始便使用SLF4J,那么这种转换将是非常轻松的事情。

      log4j的作者觉得jcl不好用,自己又写了一个新的接口api,那么就是slf4j。关于slf4j的集成图如下所示

      

      如图所示,应用调了sl4j-api,即日志门面接口。日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!

      使用SLF4J时,如果你需要使用某一种日志实现,那么你选择相对应的SLF4J的桥接包即可。比如使用log4j日志组件,就选slf4j-log4j12桥接包,业务中就可以使用log4j进行底层日志输出。

      SLF4J提供的桥接包:
        • slfj-log4j12.jar (表示桥接 log4j)
        • slf4j-jdk14.jar(表示桥接jdk Looging)
        • sIf4j-jcl.jar(表示桥接 jcl)
        • log4j-slf4j-impl(表示桥接log4j2)
        • logback-classic(表示桥接 logback)

      logback是slf4j-api的天然实现,不需要桥接包就可以使用。与commons loging(JCL)不同的是其采用在classPath加入桥接jar包来表示具体采用哪种实现(静态绑定)

    2.1、一个项目,一个模块用log4j,另一个模块用slf4j+log4j2,如何统一输出 

      这种情况很常见。因为不懂底层的日志原理,日志文件里头既有log4j.properties,又有log4j2.xml,各种API混用,还有人用着jul的API,这里主要用slf4j的适配器,slf4j提供了各种各样的适配器,用来将某种日志框架委托给slf4j。其最明显的集成工作方式有如下:

        

      进行选择填空,将我们的案例里的条件填入,显然应该选log4j-over-slf4j(表示桥接log4j2)适配器,就变成下面这张图

        

      就可以实现日志统一为log4j2来输出!

      说明:根据适配器工作原理的不同,被适配的日志框架并不是一定要删除!以上图为例,log4j这个日志框架删不删都可以,你只要能保证log4j的加载顺序在log4j-over-slf4j后即可。因为log4j-over-slf4j这个适配器的工作原理是,内部提供了和log4j一模一样的api接口,因此你在程序中调用log4j的api的时候,你必须想办法让其走适配器的api。如果你删了log4j这个框架,那你程序里肯定是走log4j-over-slf4j这个组件里的api。如果不删log4j,只要保证其在classpth里的顺序比log4j前即可!

    2.2、让spring以log4j2的形式输出

      spring默认使用的是jcl输出日志,由于你此时并没有引入Log4j的日志框架,jcl会以jul做为日志框架。此时集成图如下

        

      而你的应用中,采用了slf4j+log4j-core,即log4j2进行日志记录,那么此时集成图如下

        

      方案一:走jcl-over-slf4j适配器

        

        在这种方案下,spring框架中遇到日志输出的语句,就会如上图红线流程一样,最终以log4J2的形式输出

      方案二、走jul-to-slf4j适配器

        

      这种情况下,记得在代码中执行

    SLF4JBridgeHandler.removeHandlersForRootLogger();
    SLF4JBridgeHandler.install();

      这样jul-to-slf4j适配器才能正常工作

    2.3、死循环

      假设,我们在应用中调用了sl4j-api,但是呢,你引了四个jar包,slf4j-api-xx.jar,slf4j-log4j12-xx.jar,log4j-xx.jar,log4j-over-slf4j-xx.jar,于是你就会出现如下尴尬的场面

        

      如上图所示,在这种情况下,你调用了slf4j-api,就会陷入死循环中!slf4j-api去调了slf4j-log4j12,slf4j-log4j12又去调用了log4j,log4j去调用了log4j-over-slf4j。最终,log4j-over-slf4j又调了slf4j-api,陷入死循环!

    依赖分析:Java-idea-常用技巧-转maven,解决包依赖冲突

  • 相关阅读:
    PotPlayer直播源分享
    关于MySQL服务无法正常启动问题
    MySQL介绍及安装环境配置
    MySQL 常用命令
    Oracle【序列、索引、视图、分页】
    Oracle【二维表的维护】
    Oracle【二维表管理:约束】
    JDBC事务
    JDBC的两种sql命令发送器比较【Statement:PreparedStatement】
    mysql InnoDB存储引擎
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11064826.html
Copyright © 2011-2022 走看看