先看一张图:html
是否是有点晕, 晕就对了。这个仅仅是 slf4j 的状况,实际上, 咱们不只要接触到 slf4j ,有时候还会接触其余的日志系统。且看下文分解。java
最开始的时候, 咱们都是使用log4j, 怎么使用呢? 先引入jar,log4j-1.x.x jarapache
maven是这样的:api
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
而后配置: 配置文件主要是 log4j.properties, 具体略app
而后代码中使用框架
static org.apache.log4j.Logger logger = org.apache.log4j.LogManager.getLogger(TestLog.class);
有时候咱们也使用Apache的 commons-logging ,也就是 Jakarta Commons Logging,简称 JCL。commons-logging其实也是一个日志 接口,不是一个日志控件,没有日志功能,它只是统一了JDK Logging与Log4j的API,并把日志功能交给JDK Loggings或者是log4j 。maven
commons-logging可以选择使用Log4j仍是JDK Logging,可是他不依赖Log4j,JDK Logging的API。若是项目的classpath中包含了log4j的类库,就会使用log4j,不然就使用JDK Logging。使用commons-logging可以灵活的选择使用那些日志方式,并且不须要修改源代码。spa
怎么使用呢? 首先须要一个 commons-logging-1.2.jar, 而后引入 log4j的类库,或者不引入直接JDK Logging(这里的 log4j的类库 应该是 指log4j-1.x , 对于 log4j2 不知道是否支持 ).net
参考 :https://blog.csdn.net/u011794238/article/details/50747953 日志
maven是这样的:
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
配置:主要是 commons-logging.properties,具体略
关于 commons-logging ,其实也是一个 slf4j 相似的日志接口系统,至于其原理,请参考其余的博客,
后面出了个log4j2,log4j2是怎么使用的? 仍是先引入jar : log4j-api-2.x.x.jar和log4j-core-2.x.x.jar
maven是这样的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
没错,引入一个 log4j-core 便可, log4j-core 会自动引入 log4j-api,另外我发现这么一个jar:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j</artifactId> <version>2.8.2</version> </dependency>
仔细看一下,这个仅仅是一个pom 不是jar,也就是 log4j-core 的parent 。
而后配置: 配置文件主要是 log4j2.xml ( 有时候也能够是 log4j.xml, 或其余名字 ), 具体略
而后代码中使用
static org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(TestLog.class);
注意看到 log4j 、log4j2 的差异仍是比较大的, log4j须要一个 jar,log4j-1.x.x jar ,并且是 1.x.x 的格式, 最高好像也就是1.7.25 , 我是没有看到 log4j-2.x的 jar 的。 可是到了 log4j2,jar 的命名发生了很大的变化: log4j-api-2.x.x.jar和log4j-core-2.x.x.jar ,没有 log4j-2.x .jar , 并且也不是一个jar ,是分开了2个。
后面又来了一个 logback, logback 是天生就和slf 紧密结合在一块儿的,没法分开。(观察发现logback也没有提供任何的 Logger 实现,logback-core 的功能主要就是实现了很大的 appender ,pattern 等)通常咱们须要引入logback-classic , 它直接依赖了 logback-core、slf4j-api , 因此,咱们须要3个jar 。
maven是这样的:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
而后配置: 配置文件主要是 logback.xml , 具体略
而后代码中使用,(只能经过slf4j 的api )
static Logger logger = LoggerFactory.getLogger(TestLog.class);
直接用 jul 的人应该不多了吧。不过这里仍是要说明一下。具体 怎么使用呢?首先,它是jdk 自带的,不须要引入jar:
而后配置: 默认配置文件是logging.properties,logging.properties 通常位于 jdk或者jre 的lib 目录, 一个 jdk或者jre 只有一个配置。具体略
而后代码中使用
static java.util.logging.Logger logger = java.util.logging.Logger.getLogger(TestLog.class.getName());
logger.info("in");
logger.severe("severe");
logger.fine("fine");
能够看到它的 Logger 是 java.util.logging 包(简称 JUL)下面的, 是jdk 自带的。 不过须要注意的是 JUL的Logger 提供的方法和其余的框架的还不同。
它的日志是这样的:
四月 11, 2019 1:52:46 下午 com.lk.TestLog main 信息: in 四月 11, 2019 1:52:46 下午 com.lk.TestLog main 严重: severe
能够看到其中的月份和 日志级别都使用了 汉字, 很是的明显的 特征。
前面都是直接使用的方式(除了logback), 若是咱们统一到 slf4j 呢?这里说的是统一到 slf4j是指 代码中使用 slf4j的API。 首先咱们要明白,slf4j 是什么? 它是一个统一的日志接口框架,这样说可能仍是有些懵逼。 怎么说呢, 能够简单理解为它提供了几个关键的接口,可是没有实现他们。 因此说它只是一个 日志接口。一般咱们须要 slf4j 结合其余日志框架来打印咱们的日志。 老实说,这样作TM有些奇特, 这样作的主要目的是 方便的替换 咱们日志框架的实现, 而不用修改代码—— 其实这样的需求也是很是少的。
无论怎么说,slf4j 已然成为了主流。
几乎全部的其余日志框架均可以做为 slf4j 日志接口的实现。怎么使用呢? 一般咱们须要首先引入 slf4j-api-1.x.x.jar ( 目前来看, 主要有 1.5,1.6,1.7 三个实现,1.5 有些特别, 兼容性不是很好), 而后引入具体的实现的 jar。
有哪些实现?
NOP, 也就是No Operation,也就是不作任何操做。不须要引入任何其余jar,配置文件也是无。
logback,前文已述
simple,意味着简单。它很是简单的实现, 须要引入slf4j-simple-1.7.5.jar,
maven是这样的:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.12</version> </dependency>
slf4j-simple 依赖了 slf4j-api 。slf4j-simple 一般只是把日志直接打印到 控制台。
配置是:simplelogger.properties 或者经过D系统参数。
其实就是把日志操做 转接给了 jdk , 也就是 jul , 须要 slf4j-jdk14-1.x.x.jar ,
maven是这样的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency>
slf4j-jdk14 依赖了 slf4j-api 。
配置同直接使用JUL的场景
具体日志工做交给了 log4j , 须要 slf4j-log4j12-1.x.x.jar (主要是 slf4j-log4j12-1.6.x.jar, slf4j-log4j12-1.7.x.jar), log4j-1.2.x.jar ,
maven是这样的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
slf4j-log4j12 依赖了slf4j-api 和 log4j12 。
配置同直接使用log4j的场景
依赖 log4j2 , 须要 log4j-slf4j-impl-2.x.x.jar , log4j-api , log4j-core ,
maven是这样的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.8.2</version>
</dependency>
log4j-slf4j-impl 依赖了slf4j-api 和 log4j-api, 可是并无依赖 log4j-core , 所以, 咱们须要手动引入 它 。
配置同直接使用log4j2的场景
依赖 commons-logging , 须要 slf4j-jcl ,
maven :用得少,略
配置:略
变态的还不只仅是这个, 有时候,咱们还须要 反向的 日志操做。好比 咱们有代码已经直接使用的 log4j 的api, 可是想使用 slf4j 的实现,怎么办呢? 能够 先引入 log4j 的api的jar, 而后引入 slf4j-api , 而后引入 slf4j 的具体实现(如上), 好比 log4j 的接口,slf4j 作桥接, logback 的实现, 这个是彻底能够的。 (这能够达到一种奇特的效果, 整个系统中, 虽然有各类第二方、三方框架, 他们直接使用各类各样的 日志api, 可是我均可以让他们 统一使用 logback的实现, 也就是 只使用一个 配置便可: logback.xml , 能够减小配置量)
可是, 咱们确定不会说, log4j 的接口,slf4j 作桥接, 而后又采用 log4j 做为slf4j 的实现。看起来行得通, 实际上会出现 循环引用的问题,
这种作法,其实有点绕,容易让人迷糊。也许是我见识短浅,我其实没有直接使用过这样作法。 不过, 如今中 确实也有这样的需求。
具体来讲 也有不少种, log4j, log4j2, jcl,jul,等等。可是 咱们彷佛找不到 logback 桥接给 slf4j 的状况,我感受是由于logback 没有直接使用的接口,它天生就是和slf4j 紧密联系的。
对于 log4j, 咱们首先须要log4j的 api接口: log4j-over-slf4j-1.7.x.jar, 其余的就交给了 slf4j ———— 你可能有疑问, log4j 的接口在哪里呢? 没错,就是 log4j-over-slf4j-1.7.x.jar ,这里咱们没有使用 log4j-1.x.x jar,由于 log4j-1.x.x jar 包含了 log4j 的实现,咱们不须要它,咱们须要排除它。 这种作法简直难以想象, 不过它就是这么发生了!
maven是这样的:
<dependency> <groupId>org.slf4j</groupId> <version>1.7.21</version> <artifactId>log4j-over-slf4j</artifactId> </dependency>
log4j-over-slf4j 依赖了slf4j-api。
至于桥接到slf4j 以后的工做,好比配置文件啊,还须要的其余jar 啊,请参考前文。总之, 不要出现了 循环引用便可。
另外,我注意到, 若是 log4j-over-slf4j 、 log4j-1.x.x jar 若是同时存在于 maven 的pom ,或者classpath, 那么 究竟是启用哪个呢? 对应 maven, 答案是, 哪一个先出如今pom中 就启用哪个!
须要重要的是: log4j-over-slf4j.jar 不能和 slf4j-log4j12.jar 同时存在于 classpath 中, 不然
对于 slf4j-log4j12-1.7.25.jar :出现
Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError.
slf4j-log4j12-1.7.25.jar 比较温和,有检测机制, slf4j-log4j12-1.7.25.jar 以前的 slf4j-log4j12-1.x.x jar 则是直接抛出 异常:
java.lang.StackOverflowError at java.util.HashMap.hash(HashMap.java:338) at java.util.HashMap.get(HashMap.java:556) at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:67) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358) at org.apache.log4j.Category.<init>(Category.java:57) at org.apache.log4j.Logger.<init>(Logger.java:37) at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:43) at org.apache.log4j.LogManager.getLogger(LogManager.java:45)
除了log4j, 我想其余日志框架也是如此,不能出现over-slf4j 以后出现循环委托的状况。
log4j 是 1.x 时代了, 若是是 log4j2 呢? 咱们首先须要log4j2的 api接口:log4j-to-slf4j-2.x.x.jar,
maven是这样的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.1</version>
</dependency>
log4j-to-slf4j-2.x.x.jar 依赖了slf4j-api 和log4j-api ( log4j-api 是log4j2 的api 接口 ), log4j-to-slf4j-2.x.x.jar 没有依赖 log4j-core。 那么 log4j2 是怎么反向桥接到 slf4j 上去的呢? 其实这个是 log4j-to-slf4j 的功劳,log4j-to-slf4j-2.x.x.jar 桥接了 log4j-api ,而后具体实现交给了 slf4j。
特别注意到:log4j-1.x 的桥接jar 名是这样的: log4j-over-slf4j 而log4j-2.x 的桥接jar 名是这样的: log4j-to-slf4j, 名字很是相近。
至于桥接到slf4j 以后的工做,请参考前文。
前面说过使用 SLF4J的API, 而后 使用JCL的实现, 反过来也是能够的。
jcl 并非jul, 不是 java.util.logging 而是 org.apache.commons.logging , 也就是 commons-logging 的那一套。 为此, 咱们须要一个 jcl-over-slf4j-1.x.x.jar
maven是这样的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
至于桥接到slf4j 以后的工做,请参考前文。
JUL 和 JCL 是仅仅一字之别,可是千万不能搞混啊!它是将 jdk logging API 打印的日志交给了 slf4j,咱们 须要一个 jul-to-slf4j-1.7.x.jar
maven是这样的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
代码中还须要作一些修改:
须要先执行下面的:
static{ SLF4JBridgeHandler.install(); }
不过从打印的结果, 我看到 日志打印了两次, 彷佛哪里出了问题,并无达到想要的效果。
四月 11, 2019 6:40:12 下午 com.lk.TestLog main 信息: in 18:40:12,318 [com.lk.TestLog] - severe --- log4j的日志
四月 11, 2019 6:40:12 下午 com.lk.TestLog main 严重: severe
须要注意的是 咱们并无 jul-over-slf4j 的jar, 这个多是命名的历史缘由, 暂时 jul-to-slf4j 能够理解为就是 jul-over-slf4j ...
至于桥接到slf4j 以后的工做,请参考前文。
这样的需求也是有的,作法确定也是有的,也确定有人实现了的。好比,貌似 feign 也有一个实现,gossip 也有:
这些jar我没有用过,具体,就很少说了。
关于SLF4J 其实也能够写不少,还有JCL( 也就是commons-logging)具体的原理这里很少讲了,请参考其余的博客。总之,感受这整个java 的日志系统 仍是挺麻烦的,特别是其中的jar的命名,不太规律,容易混淆,不容易记住。搞来搞去, 容易把人搞晕呢,这个时候 就须要看其源码! 其实其中不少jar 的实现是很简单的,也就几个类,特别是那些桥接的jar, 一打开看一下就明白了,哦,说得也是呢!
看个人文章后是否是有所收获呢?是否是应该点32个赞鼓励一下呢?
参考:
https://my.oschina.net/pingpangkuangmo/blog/410224https://www.slf4j.org/legacy.htmlhttps://blog.csdn.net/u011794238/article/details/50747953https://blog.csdn.net/john1337/article/details/76152906http://www.cnblogs.com/chen310/p/4216316.htmlhttps://blog.csdn.net/u011794238/article/details/50783188https://blog.csdn.net/u011794238/article/details/50771488