阿里面试:说了多少遍要用门面模式的日志框架?

2023年 9月 22日 75.6k 0

📣 大家好,我是Zhan,一名个人练习时长两年的大三后台练习生🏀

📣 这篇文章是 Java 日志框架 的第一篇学习笔记📙

📣 如果有不对的地方,欢迎各位指正🙏🏼

📣 以始为终 —— Just do it!  🫵🏼🫵🏼🫵🏼

👉引言

如何理解《阿里巴巴 Java 开发手册》中的 门面模式的日志框架,以及它如何做到处理方式的统一?

其实 Java 日志框架是有它的生态的:SLF4J 本身不提供日志的实现,Logback 给 SLF4J 提供门面的支持,也就是说日志框架是分为 门面框架 和 实现框架,他们之间又是怎么实现的呢,本文将会告诉你答案。

一、门面框架和实现框架

有点类似于接口和实现类的关系,门面框架和实现框架其实就是这样的关系:提供通用的日志 API 给调用方,而自己去实现不同日志框架的适配,这种设计模式叫做 外观模式,MySQL 的驱动设计其实也是这种思想

了解了日志框架的基本思想之后,就可以方便我们构造知识体系,究竟哪些框架是门面框架、哪些是实现框架:

🚪 门面框架

  • SLF4J:
    • 它本身不提供日志实现,仅仅提供“门面”,这点我们可以从它的名字中得到:
    • Simple Logging Facade For Java(Java 的简单日志门面)
    • 对应的日志实现框架:Log4j、Logback、JUL……
  • Apache Commons Logging
    • 通常与 Apache Log4j 1.x 结合使用
  • 🔑 实现框架

  • JUL(java.util.logging)
    • 它是 Java 标准库中自带的 API,只能进行简单的日志记录
    • 也就是说它是一个简单“实现框架”,它并没有所谓的门面框架,也就是开发人员可以直接使用 JUL 提供的日志记录API
  • Apache Log4j
    • 它存在两个版本——log4j1 log4j2
    • Log4j1 不需要显示的门面支持,但是可以和 Apache Commons Logging 结合使用,以提供门面的支持
    • Log4j2 通常与 SLF4J 结合使用,也就是 SLF4J 的实现框架
  • LogBack
    • 它是 SLF4J 的实现框架,同样也是我们通常使用的组合,因为它们提供了良好的性能和灵活性
  • 🎯 注意点

    尽管日志门面框架提供给通用的日志 API 给调用方,但是这是不包括每个日志实现框架的配置

    也就是说日志门面框架可以帮助我们使用统一使用 API,但是选用对应的实现框架也要配置对应的文件

    二、SLF4J 是怎么实现它的“门面”的?

    尽管我们了解了什么是门面框架,什么是实现框架,类比一下接口和实现类就能很好理解,但是它是怎么实现这个 外观模式 的呢?

    我们可以看一下这张图,图中的绿框就是我们使用的 Spring 程序,而剩下的部分:

    • Spring程序默认使用 JCL 框架(图中的 Commons Logging API 也就是浅蓝色部分)

    • JCL 框架还可以和 Log4j1 一同使用(图中的灰色部分)

    • 还有可以直接在程序中打印的 JUL 工具类(图中的灰色部分)

    也就是说 Spring 这个 Application 会产生这三类日志。

    而我们想使用 LogBack 作为实现框架,这就不免产生了一些冲突,SLF4J 是怎么做的呢?

    • JCL 门面框架:可以引入 jcl-over-slf4j,也就是 JCL 桥接器,它会把 JCL 的日志消息重定向到 SLF4J,从而让 SLF4J接管这些日志信息
    • Log4j1:使用 jcl-over-slf4j 库,把调用 Log4j 打印日志的地方适配成 SLF4J 的API
    • JUL:同样是这个库,实现自定义的处理器,把 JUL 打印日志的地方进行适配的处理

    我们如果使用 LogBack 作为日志的实现框架,也就是图中的蓝色部分:

    注意:而如果我们使用 LogBack 作为实现框架,LogBack 的库中,内置了对 SLF4J 框架的实现,也就是实现了 SLF4J 提供的标准,因此可以直接调用

    三、SpringBoot 日志框架的封装

    Spring 采用 JCL 日志门面框架来记录日志,而 SpringBoot 保持和 Spring 一致,但是它提供了对 JUL、Log4j2、LogBack 日志实现框架的封装,提供默认的日志配置,我们可以从下面这个例子中证明上述的观点:

    我们每次在启动 SpringBoot 项目的时候都会有这一信息:

    2019-12-29 17:24:57.935 INFO 97606 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''  
    2019-12-29 17:24:57.938 INFO 97606 --- [ main] c.i.s.lab36.prometheusdemo.Application : Started Application in 2.624 seconds (JVM running for 3.228)  
    2019-12-29 17:24:58.412 INFO 97606 --- [on(4)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
    

    其实这个日志是通过 LogBack 打印出来的,为什么这么说呢,在 DefaultLogbackConfiguration 中,定义了日志的格式,也就是说 SpringBoot 做了默认的 LogBack 的配置:

    private static final String FILE_LOG_PATTERN = "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} "  
    + "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";
    

    也就是:日期 + 日志级别 + 进程ID + 线程名 + 源类 + 日志内容

    而这些日志的配置是可以通过配置文件进行配置的:

    • logging.pattern.file:文件的日志格式
    • logging.pattern.console:控制台的日志格式
    • logging.pattern.dateformat :日期和时间。
    • logging.pattern.level :日志级别。
    • logging.pattern.pid : 进程 ID。

    配置文件指的是 application.yml 吗?其实不然,配置文件其实是不同的日志实现框架拥有不同的配置文件名称,可以理解为各个框架和Spring约定俗成:

    • LogBack:logback-spring.xmllogback.xml
    • Log4j2:log4j2-spring.xmllog4j2.xml
    • JUL:logging.properties

    SpringBoot 中集成了这么多日志的框架,其中主要就是两种实现日志的方式,而我们选用的方式就是通过日志相关的 Starter 进行选用:

    • spring-boot-starter-logging :使用 SLF4J + Logback 的组合
    • spring-boot-starter-log4j2 :使用 SLF4J + Log4j2 的组合。
      而我们默认情况下会使用 SLF4J + LogBack 的组合

    💬 总结

    本文主要讲解了 Java 中日志框架的生态:实现框架、门面框架,可以类比接口和实现类,而需要注意的是,尽管使用了门面框架,还是需要对实现框架进行配置,门面框架只是统一了 API。

    如果说在看这篇文章之前,还分不清 SLF4J、Log4j、LogBack 这些日志框架,相信看完本文你能知道它们各自的使用场景和特点。

    而对于 SLF4J 这个最常用且出名的门面框架,我们讲解了它对 JUL、Log4j1、JCL 框架的兼容的方式。

    最后简单了解了一下 SpringBoot 日志框架的使用以及一些简单的配置,而下一篇文章我们会详细介绍 SpringBoot 的日志使用,敬请期待!

    🍁 友链

    • 芋道 Spring Boot 日志集成 Logging 入门
    • Log4j Bridge (slf4j.org)
    • 外观模式 | 菜鸟教程 (runoob.com)
    • 如何优雅地记录操作日志? - 美团技术团队 (meituan.com)
    • (二)日志规约 - 阿里巴巴Java开发手册 (oschina.io)

    ✒写在最后

    都看到这里啦~,给个点赞再走呗~,也欢迎各位大佬指正以及补充,在评论区一起交流,共同进步!也欢迎加微信一起交流:Goldfish7710。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论