一文理清slf4j-api、slf4j-xxx之间的关系(Java日志框架体系)

569 阅读2分钟

slf4j 统一Java日志体系

slf4j(Simple logging Facade for Java) 只是提供了一个抽象层,我们编码的时候依赖抽象层,而运行时可以使用任意一个日志实现框架(log4j、reload4j等)。

因此,当我们只引用slf4j-api而不引入实现框架时,编译运行会报错没有引入具体的实现类(Provider)。 image.png

slf4j-xxx 连接抽象和具体的桥梁

slf4j-xxx 是slf4j-api和xxx日志实现之间的适配器。以reload4j为例,slf4j-reload4j就是slfj4j-api和reload4j之间的适配器。

slf4j-xxx的一种实现方法是继承StaticLoggerBinder,logback框架采用了这种方式适配,核心实现原理见如下代码:

// 这段源码来自slf4j-api LoggerFactory的bind()方法
Set<URL> staticLoggerBinderPathSet = null;
if (!isAndroid()) {
    staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
    reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// 初始化StaticLoggerBinder
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = 3;
reportActualBinding(staticLoggerBinderPathSet);

findPossibleStaticLoggerBinderPathSet会搜索当前classpath下实现了StaticLoggerBinder的包(通常是slf4j-xxx),然后初始化StaticLoggerBinder并获取LoggerFactory,进一步由LoggerFactory创建具体的Logger(通常是日志实现类)。

还有一种方法是实现SLF4JServiceProvider,reload4j就是采用这种方式适配的。感兴趣的看客可以自己打断点分析,这里不做展开,

百家争鸣 - 具体实现层

log4j、log4j2、reload4j、logback等 都是具体的日志实现类,笔者印象里log4j2是log4j的官方升级版,reload4j是log4j的拓展版,reload4j提供了日志配置热加载(修改日志配置后无需重启即可生效,原理是额外起一个监听线程定时检查配置文件),而log4j2也推出了这个特性。总之,这些日志框架之间属于互相演进关系,对于更多的特性差异本文不做展开。

举个例子

当前项目开发时需要引用zookeeper,zookeeper原生依赖logback但是代码依赖slf4j,而当前项目引用的是reload4j,依赖关系如下图: image.png 那么就可以大胆去掉zookeeper包中的logback包,slf4j提供的抽象层会自动将reload4j实现无缝接入zookeeper中。

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.8.0</version>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.9</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-reload4j</artifactId>
    <version>2.0.9</version>
</dependency>
<dependency>
    <groupId>ch.qos.reload4j</groupId>
    <artifactId>reload4j</artifactId>
    <version>1.2.22</version>
</dependency>

总结

slf4j是抽象层,对程序员提供统一日志入口,slf4j-xxx是桥梁层,连接slf4j-api和具体日志实现层。总之,只要我们依赖的软件包依赖于slf4j,slf4j就能轻松帮助我们解决复杂的日志框架冲突问题。

最后上一张祖传架构图加深印象。

image.png