美文网首页
JAVA中的日志slf4j从0到1(slf4j-log4j和lo

JAVA中的日志slf4j从0到1(slf4j-log4j和lo

作者: 小胖学编程 | 来源:发表于2021-01-08 11:34 被阅读0次

    简短地描述下日志发展,最先出现的是apache开源社区的log4j,这个日志确实是应用最广泛的日志工具,成为了java日志的事实上的标准。然而,当时Sun公司在jdk1.4中增加了JUL日志实现,企图对抗log4j,但是却造成了混乱,这个也是被人诟病的一点。当然也有其他日志工具的出现,这样必然造成开发者的混乱,因为这些日志系统互相没有关联,替换和统一也就变成了比较棘手的一件事。想象下你的应用使用log4j,然后使用了一个其他团队的库,他们使用了JUL,你的应用就得使用两个日志系统了,然后又有第二个库出现了,使用了simplelog。这个时候估计让你崩溃了,这是要闹哪样?这个状况交给你来想想办法,你该如何解决呢?进行抽象,抽象出一个接口层,对每个日志实现都适配或者转接,这样这些提供给别人的库都直接使用抽象层即可。不错,开源社区提供了commons-logging抽象,被称为JCL,也就是日志框架了,确实出色地完成了兼容主流的日志实现(log4j、JUL、simplelog),基本一统江湖,就连顶顶大名的spring也是依赖了JCL。看起来事物确实是美好,但是美好的日子不长,接下来另一个优秀的日志框架slf4j的加入导致了更加混乱的场面。比较巧的是slf4j的作者(Ceki Gülcü)就是log4j的作者,他觉得JCL不够优秀,所以他要自己搞一套更优雅的出来,于是slf4j日志体系诞生了,并为slf4j实现了一个亲子——logback,确实更加优雅,但是由于之前很多代码库已经使用JCL,虽然出现slf4j和JCL之间的桥接转换,但是集成的时候问题依然多多,对很多新手来说确实会很懊恼,因为比单独的log4j时代“复杂”多了,可以关注下这个,抱怨声确实很多。到此本来应该完了,但是Ceki Gülcü觉得还是得回头拯救下自己的“大阿哥”——log4j,于是log4j2诞生了,同样log4j2也参与到了slf4j日志体系中,想必将来会更加混乱。

    1. 日志框架的选择

    1. 在非特殊的情况下,项目使用slf4j-api+logback。接入方式推荐SpringBoot2.x整合logback日志框架(1)
    2. 对于要提供给别人的类库,建议使用slf4j-api,使用方可以自由选择具体的实现,并且建议类库不要依赖具体的日志实现,maven依赖如下图:
            <!-- 日志接口类-->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </dependency>
    
    1. 项目中具体的使用,如下面代码:
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class XxTemplate {
    
        //顶级接口,实现依赖于具体的子类
        private static final Logger logger = LoggerFactory.getLogger(XxTemplate.class);
        public void get() {
            logger.info("打印参数");
        }
    }
    

    2. slf4j的设计

    slf4j:Simple Logging Facade for Java,为java提供的简单日志Facade。Facade门面,更底层一点说就是接口。它允许用户以自己的喜好,在工程中通过slf4j接入不同的日志系统。

    在简述中,可以知道日志发展是比较混乱的,slf4j作者想将世面的多种日志框架整合起来。对于slf4j前的具体实现。提供了一些桥接类,如下图:

    image.png
    • 每个系统的日志顶级接口都是slf4j-api。

    • 第三层的深蓝色块,是具体的日志实现。他们本身都实现了slf4j API。slf4j-simple.jar和slf4j-nop.jar这两个不用多说,看名字就知道一个是slf4j的简单实现,一个是slf4j的空实现,平时用处也不大。而logback之所以也实现了slf4j API,据说是因为logback和slf4j出自同一人之手,这人同时也是log4j的作者。

    • 第三层的浅蓝色块,是适配器,左边的slf4j-log4j12.jar桥接器看名字就知道是slf4j到log4j的桥接器,同样,右边的slf4j-jdk14.jar就是slf4j到Java原生日志实现的桥接器了。它们的下一层分别是对应的日志框架实现,log4j的实现代码是log4j.jar,而jul实现代码已经包含在了JVM runtime中,不需要单独的jar包。

    • 第三层中灰色的jar包块都实现了slf4j API,只是浅蓝色的桥接器快对slf4j API的实现并不是直接输出日志,而是转去调用别的日志框架的实现。

    3. slf4j的实现原理

    slf4j-api和具体的实现类是在编译时进行绑定的,slf4j-api中会去调用StaticLoggerBinder这个类获取绑定的工厂类,而每个日志实现会在自己的jar中提供这样一个类,这样slf4j-api就实现了编译时绑定实现。

    slf4j-api的pom文件,在打包的时候,将该类删除,最终走子类实现的StaticLoggerBinder类。

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <executions>
              <execution>
                <phase>process-classes</phase>
                <goals>
                 <goal>run</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
              <tasks>
                <echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
                <delete dir="target/classes/org/slf4j/impl"/>
              </tasks>
            </configuration>
          </plugin>
    
    包里没有该文件.png

    打出来的slf4j-api是不完整的,只有找到包含StaticLoggerBinder这个类的包才可以,于是slf4j-log4j和logback-classic都提供了这个类。另外,slf4j-log4j和logback以及slf4j-jdk14是不能同时和slf4j共存的,也就是说只能有一个实现存在,不然启动会提示有多个绑定。

    推荐阅读

    相关文章

      网友评论

          本文标题:JAVA中的日志slf4j从0到1(slf4j-log4j和lo

          本文链接:https://www.haomeiwen.com/subject/qybxaktx.html