很偶然的机会,发现了slf4j。同事在引入的其他包与现存的log4j产生冲突,只要加入这些包,原来的log4j就会失去作用,原来能够打印的日志,现在都不输出了。一时不知道该怎么办。
后来在仔细查看日志,发现打印出来的信息有slf4j加载失败的信息。所以到网上搜索。可是,如果就加入某个包,是如何影响我的log输出的呢?
SLF4J,即简单日志门面(Simple Logging Facade for Java)。从设计模式的角度考虑,它是用来在log和代码层之间起到门面的作用。对用来来说只要使用slf4j提供的接口,即可隐藏日志的具体实现。这与jdbc和相似。使用jdbc也就避免了不同的具体数据库。使用了slf4j可以对客户端应用解耦。因为当我们在代码实现中引入log日志的时候,用的是接口,所以可以实时的更具情况来调换具体的日志实现类。这就是slf4j的作用。
SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类。SLF4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。
配置SLF4J是非常简单的一件事,只要将与你打算使用的日志系统对应的jar包加入到项目中,SLF4J就会自动选择使用你加入的日志系统。
日志系统绑定原理:
在应用中,通过LoggerFactory类的静态getLogger()获取logger。通过查看该类的代码可以看出,最终是通过StaticLoggerBinder.SINGLETON.getLoggerFactory()方法获取LoggerFactory然后,在通过该具体的LoggerFactory来获取logger的。类org.slf4j.impl.StaticLoggerBinder并不在slf4j-api-1.5.2.jar包中,仔细查看每个与具体日志系统对应的jar包,就会发现,相应的jar包都有一个org.slf4j.impl.StaticLoggerBinder的实现,不同的实现返回与该日志系统对应的LoggerFactory,因此就实现了所谓的静态绑定,达到只要选取不同jar包就能简单灵活配置的目的。所以这就解答开始的疑问。
虽然具体的机制不是很清楚,但是可以肯定的是引入的包里有slf4j。系统自动使用slf4j机制来代替了原来的日志配置,可是上面不是说了slf4j只是顶层的接口,具体实现还是由具体的log包来完成。那么为什么没有输出呢?
原来出来slf4j接口包 slf4j-api.jar 还要有一个关键性的包 slf4j-log4j12.jar 这个包就像是链接器 用来将slf4j和log4j联系在一起,所以加入该包后,日志显示正常。
从slf4j官网下载包后,里面会包含若干个与各种具体日志实现联系包。
再次探寻:
一些开源的架包 比如spring 是如何实现对具体日志解耦的呢,虽然不是使用slf4j,却是用的是Jakarta Commons Logging+log4j,也就是为什么commons-logging出现的频率如此高的原因。他的功能就是提供了底层的log接口。
SLF4J+Log4J。
需要的配置文件和组件包,下面三个 jar 文件和一个 properties 文件都是要放在项目的 ClassPath 上。
1. slf4j-api-1.5.11.jar
2. slf4j-log4j12-1.5.11.jar
3. log4j-1.2.15.jar
4. log4j.properties(也可以是 log4j.xml,本例中用 log4j.propertes)
package com.unmi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestSlf4j {
private static final Logger logger = LoggerFactory.getLogger(TestSlf4j.class);
public static void main(String[] args)
{
logger.info("Hello {}","SLF4J");
}
}