• Java 8之后的那些新特性(三):Java System Logger


    去年12月份log4j日志框架的一个漏洞,给Java整个行业造成了非常大的影响。这个事情也顺带把log4j这个日志框架推到了争议的最前线。

    在Java领域,log4j可能相对比较流行。而在log4j之外,Java程序员可能还会知道或听到类似jul,slf4j,logback的一些日志框架。

    但实际上,还有另外一个可能相当多的程序员不知道的就是:

    Java 9引进了日志标准接口System Logger

    本文是Java 8之后的那些新特性系列的第三篇。本系列其它文章为:

    1. Java 8之后的那些新特性(一):局部变量var
    2. Java 8之后的那些新特性(二):文本块 Text Blocks

    JUL

    事实上,除了流行的log4j,slf4j这些日志框架以外,Java其实在1.4的版本中就引进了java.util.logging日志实现。

    但这个Java自带的日志事实上并未流行起来,今天知道它的远比知道log4j这些流行日志框架的少。

    如果用代码来说话,java.util.logging示例如下:

    import org.junit.jupiter.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class TestJavaUtilLogging {
    
        private static Logger logger = Logger.getLogger(TestJavaUtilLogging.class.getName());
    
        @Test
        void testLogger(){
            logger.log(Level.INFO,"这是一个java.util.logging.Logger日志");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这个日志工具类没有流行起来的原因,在于它有许多的问题,最大的一个是其性能远远比不上log4j。

    log4j,事实上的主流

    在相当长的一段时间内,至少是在Java 8占主流的Java世界中,关于日志这一块,Java自身是没有任何标准的,而java.util.logging是一个实现,而不是标准,而且几乎是一个不太为人所知的实现。

    参照来说,在Java的世界中,有两个标准是我们程序员非常熟悉的。

    其一是JPA标准,hibernate也好,eclipselink这些都实现了JPA标准。而大家用的非常多的Spring Data Jpa其实是基于hibernate再封装了一层。

    另一个就是javax.annotation。类似Spring Bean IOC框架,Guice依赖注入框架,它们同样都支持了javax.annotaion。

    而在Java日志系统这个领域,很长一段时间,本身并未有标准。

    用的最多的log4j,成为了事实上的主流。

    slf4j,试图定义一个标准

    我认为有相当一部分人对slf4jj这个认知可能并不是很正确,把它当成和log4j一样的日志框架去理解。

    但其实并不是。slf4j理论上并不能和log4j,logback放在一起说,它们是不同级别的东西。

    slf4j的全称是:The Simple Logging Facade for Java,用中文来描述就是,Java简单日志门面

    slf4j并不是一个日志实现,它是接口与抽象,它的角色非常类似于JPA以及javax.annotation这样的东西。 虽然slf4j自身提供了一个默认的空实现,但那其实什么意义都没有。

    你必须将slf4j + log4j或者slf4j + logback这样的搭配起来用才行。slf4j是接口,而log4j与logback是实现。

    是不是和JPA很相似?是的,slf4j的目的就是希望给Java带来一个日志标准。

    其实,它确实成为了Java当前业界事实上的标准了,主流的第三方日志框架都实现了slf4j中的接口。那些就算使用了log4j做为实现的,也大多会与slf4j结合使用。

    所以,你在Java的第三方类库中,可能见到的大部分Logger类,大多是org.slf4j.Logger,而org.slf4j.Logger其实是一个接口。同样,在使用slf4j的时候,你一定会见到log4j或logback等日志实现搭配一起来用。

    Java System Logger

    不过,slf4j毕竟不是JDK的东西,也不属于javaEE,是属于apache的开源框架。

    Java仍然希望建立自己JDK级别的日志标准,这样会有以下几个好处:

    1. 结束当前Java生态中日志混乱不统一的现状
    2. 提供SDK级别的日志接口,有利于生态中的所有类库后续都只依赖SDK日志接口,这样可以做到任意切换日志实现。

    当然,这个想法确实很不错,而且Java确实也这么做了。

    终于,在Java 9的时候,Java 9添加了System Logger特性。这个日志接口的完整类名是: java.lang.System.Logger

    System.Logger同样是一个接口,不是实现。这意味着你需要一个实现。

    如果你没有添加另外的实现,则默认使用的是java.util.logger.Logger做为实现。

    当然,你也可以使用log4j来做实现,log4j也添加了对Java System Logger的实现.

    添加log4j及log4j-jpl依赖 (以Gradle为例)

        dependencies {
            testImplementation("org.apache.logging.log4j:log4j-core:${rootProject.extra["log4j-version"]}")
            testImplementation("org.apache.logging.log4j:log4j-jpl:${rootProject.extra["log4j-version"]}")
        }
    
    • 1
    • 2
    • 3
    • 4

    同样,添加log4j.properties日志配置文件

    log4j.rootLogger=INFO,stdout
    log4j.logger.org.myddd=DEBUG
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%p\t%d{ISO8601}\t%r\t%c\t[%t]\t%m%n
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    使用System.Logger做日志

    public class TestSystemLogger {
    
        private final static System.Logger logger = System.getLogger(TestSystemLogger.class.getName());
    
        @Test
        void testLogger(){
            logger.log(System.Logger.Level.DEBUG,"这是Java System Logger的Debug日志");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    甚至,你可以自己实现一个日志实现也行。

    问题

    Java 9引进这个JDK级别的Logger,从想法上来说是好的,也是值得称赞的。但如果再认真分析下,我认为它仍然有它的问题

    其一:其实现不够简洁优雅

    来,我们对比下

    // Java System Logger的写法
    logger.log(Level.DEBUG,"这是Java System Logger的Debug日志");
    
    //log4j及其它日志框架的写法
    logger.debug("这是log4j的Debug日志");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    一眼就可以看到,从简洁性上来说,log4j这种更简洁。

    在简洁代码之道中也专门说到这个,与其通过多一个参数,还不如多几个方法,减少一个参数这样更简洁与优雅,方法的表意更简洁纯粹。

    其二:存在感不强,短期内难以改变日志现状

    Java 9这个System Logger,存在感我认为并不强,可能相当一部分Java程序员并不知道这个点。

    那我们可以很容易推测,基于Java的第三方类库也好,生态也好,在日志上可能仍然会选择slf4j这个抽象或干脆直接使用log4j或logback这一类的实现,而不是Java System Logger。

    这意味着,Java System Logger试图统一Java生态的日志,短期内难以实现。

    而slf4j虽然是个抽象,但肯定也有相当一部分框架可能直接使用的log4j,而不是slf4j + log4j。

    这代表着,在你的Java项目中,当你依赖众多第三方框架时,有些第三方框架可能使用的是slf4j,有些可能使用的是log4j,也有些可能使用的是其它日志。

    这种混乱的局面,短期内仍然无法改变。

    结束

    所谓"亡羊补牢,犹未迟也",虽然短期内无法改变现状,但Java的这种进步仍然值得鼓励。

    而对我而言,未来使用System Logger配类似log4j来做为实现,这是我尊重Java的最好的方式与行动了。

    你会怎么做呢?

  • 相关阅读:
    8-2插入排序-折半插入排序
    2022年最新前端面试题
    PAM从入门到精通(十二)
    【算法基础】高精度运算
    生态共建|与轻流完成产品兼容互证
    系统集成|第十二章(笔记)
    Java8 Stream使用整理
    flutter系列之:Material主题的基础-MaterialApp
    Java数组案例
    spark学习笔记(十二)——sparkStreaming-RDD队列/自定义数据源/kafka数据源/DStream转换/DStream输出/优雅关闭
  • 原文地址:https://blog.csdn.net/taoofcode/article/details/126219151