sl4j的门面模式
使用sl4j门面模式,有个很好的特性:一套代码到处运行。
现象:只要使用
// 引入sl4j类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 定义LOGGER
public static final Logger LOGGER = LoggerFactory.getLogger(类.class);
// 使用LOGGER
LOGGER.info("------info日志---------");
无论项目中使用的logback还是log4j2,用户都不需要关心。
所以阿里编程规范里也规定:
应用中不可直接使用日志系统( Log4j、 Logback) 中的 API,而应依赖使用日志框架
( SLF4J、 JCL–Jakarta Commons Logging) 中的 API,使用门面模式的日志框架,有利于维护和
各个类的日志处理方式统一。
那sl4j-api在不知道项目引用哪种日志框架的时候,是如何调用项目中的日志框架的呢。
简单来说就是:
- 项目中添加了一个sl4j-日志框架的“转接头”包。
- 在转接头包里定义一个固定类。
- sl4j-api调用这个固定的类。
下面就引出本文的一个联想主题。。。
如何调用一个“还不存在”的类
下面是我的总结:
主要分为两类:框架开发和日常应用。我们多数人,其实只要关心下半部分就可以。
一图胜千言,就不多讲了。上图中SpringBoot自动装配的内容,可以看我的另一篇博客SpringBoot自动装配串讲
我们重点说一下本文的主角sl4j。sl4j-api直接调用的一个“未知的类”。看一下源码:
以logback为例,看一下这个类实际的位置所在,在logback-classic里:
sl4j要解决的两个困难
-
sl4j-api要调用一个不存在的类。那么sl4j-api在开发阶段,项目工程里肯定要有一个临时的实现类可以被调用。然后开发完,打成jar包之后,还要把这个临时的类删除掉。否则就没法调用被用户引入的其他包里的类了。那怎么删除临时类,然后重新打包呢?下面是操作流程:
-
解压缩jar文件。可以使用以下命令解压缩jar文件:jar -xf yourjarfile.jar,其中"yourjarfile.jar"是你要解压缩的jar文件的名称。
-
进入解压后的文件夹,找到你想要删除的类所在的文件夹。删除该类的.class文件。
-
在解压后的文件夹中重新打包jar文件。你可以使用以下命令重新打包jar文件:jar -cf yourjarfile.jar *,其中"yourjarfile.jar"是你要重新打包的jar文件的名称(这里的星号表示打包当前目录中的所有文件及文件夹)。
-
-
sl4j-api直接调用类的静态方法,如果被调用的类不存在,那肯定是会报错的。如何在调用之前判断一下用户有没有引入正确的包呢?朴素的想法就是在项目里找找有没有这样的类。如果没有,则直接结束程序。如果引入了多个(比如同时引入里logback和log4j)也提醒一下用户(jvm会随机挑一个执行)。那怎么找class文件呢?
用ClassLoader.getResources(一个classLoader类里找class文件的方法,有静态的方法,也有非静态的方法)。
ClassLoader.getResources
这个方法可以传入一个确定的全类名,在classpath里找找到这个class文件。sl4j就是这么做的,看下图:
如果用户引用了两个实现类,那么上图中的paths就会获取到两个。后面就会通过日志告诉用户这个问题(但并不影响使用,jvm会随机挑一个执行)
也可以传入一个path目录,找目录下的所有class。Spring在扫描包下的所有类时,用的就是这个方法,看下图:
问:既然Spring是个容器,可以从自己的容器里根据接口找对象。那么ClassLoader也可以视为一个容器(一个装类的容器)。那么为什么没有类似Spring的getBeansOfType方法?
因为:JVM是“懒加载”,只有在第一次使用时,才会加载对应的类。 即使是Spring的getBeansOfType也不能保证获取到所有接口的实现类,Java更不会提供这种不确定的方法了。
感想
为什么sl4j要用门面模式?
为什么日志类的包那么乱?
log这么基础常用,而且看起来也不复杂的东西,jdk为什么没能统一接口?
看过java日志类的历史,感觉:
初看是因为:sun公司没有远见和能力,Apache内部人心不齐,才导致日志框架混乱不堪。
深入想想:日志其实是一个很偏应用的模块。看似简单基础,但要一下子做的尽善尽美并不容易,需要经历很多年的项目积累。以至于sun公司和Apache都无法一下子把握住。
2021年年末,暴雷log4j2出现“核弹级漏洞”。
直接原因:log4j2中使用了JNDI技术,然后没把握住,出现了漏洞。
个人感觉:纯粹多此一举。JNDI这么危险的技术应用在日志中,但多数人听都没听说过。
软件需要足够丰富的功能,但也不要太越界,什么功能都加。尤其像日志框架这种很纯粹的软件,在满足基本功能的同时,尽量简单。
参考
Logback源码分析
源码详解系列(七) ------ 全面讲解logback的使用和源码
从0到1带你深入理解log4j2漏洞