【精品】解释JAVA五花八门的各种日志系统及关系,

 

目录

前言:

分类

介绍

javaLog

log4j

logback

Nop

slf4j

jcl

问答:

1.如果slf4j里引入了多种连接器和底层实现.那么真正执行的是谁?

2.项目日志包只加载这些,且没有配置文件,请问Spring的debug运行日志会显示出来吗?底层实现是哪个日志系统?

3.我们讲slf4j时那个连接器图里,还有个slf4j-jcl的连接器的jar,那个是将jcl作为slfj的底层实现的连接器,和jcl-over-slf4j.jar作用正好相反,如果将该jar投入到第二题环境里面。然后将logback-classic.jar删除掉,则会发生什么事情?会不会发生slf4j和jcl循环调用最终导致栈溢出呢?

4.有些依赖源码里直接使用的log4j,而我现在希望由slf4j+logback来控制所有的日志怎么办?

最优使用

结语:


前言:

 

编写目的如果你觉得你的项目里日志系统像不同动物的屎一样混在一起,那么这篇文章是你所需要的

阅读要求本文的读者要求至少使用过一段时间日志系统。对于没有使用过的,不建议你看。

其他:欢迎转载,但请注明出处。

分类

目前JAVA流行的日志系统有

Java.util.Logger 以后简称javaLog
log4j
logback
NOPlogger,以后简称Nop
slf4j
common-logger 以后简称jcl

介绍

以上6个日志系统,其中slf4j和jcl是接口是规则,相当于jdbc,其他4个是具体实现。

也就是说如果只引入了slf4j和jcl,那么日志系统是根本没有卵用的。

但是你可以不引入slf4j和jcl,而只引入其他实现,那么实现日志是可以的。(除了logback)

接下来逐一介绍。

javaLog

这个是JDK1.4的时候增加的日志类。使用起来很简单。看代码,内容很简单,打印了两行

import java.util.logging.Logger;

public class JDKLog {
	public static void main(String[] args) {
		Logger logger = Logger.getLogger("aaaa");
		System.out.println(logger.getLevel());//获取当前Log的等级
		logger.info("111111");
		logger.info("22222");
	}
}

再看下现象,这个现象很有趣,所以要截图。

如果你用过tomcat,就知道这里的打印信息和tomcat默认打印的信息简直一摸一样。说明tomcat默认使用的就是JavaLog,只是日志等级默认却是null。

javalog使用好的话比较麻烦且基本概念落伍。

log4j

apache组织的日志系统。是最火爆的,看下如何使用

import org.apache.log4j.Logger;

public class Log4jLog {
	public static void main(String[] args) {
		Logger logger = Logger.getLogger(Log4jLog.class);
		logger.info("Log4j");
		
	}
}

 如果只是这样的话,那么绝对打印不了内容,只会打印红色的警告提示,因为对于Log4j来说,配置文件是必须的。

你可以加上一个log4j.properties,然后再打印就打出来了。

logback

logback是一个log4j作者二次开发的一个更为高效快速的日志系统。但是它不能单独使用,因为它没有入口,你必须使用接口来使用它,比如slf4j或者jcl

我们接下来用slf4j来看logback如何使用的,你需要这样作。

引入且只引入以下三个包:slf4j - api.jarlogback - core.jar 和logback - classic.jar。(不要混有其他日志包,原因在slf4j里面讲。)

然后代码这样写,先不要运行。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogBackLog {
	public static void main(String[] args) {
		Logger logger = LoggerFactory.getLogger(LogBackLog.class);
		logger.info("aaaaaaaa");
		System.out.println(logger.getClass());
	}
}

如果你能认真一些,就能发现这个测试类里并没有引入logback的类,很奇怪的事情!不过还有更奇怪的事情,接下来请你运行。

18:06:08.894 [main] INFO com.bai.momo.LogBackLog - aaaaaaaa
class ch.qos.logback.classic.Logger

打印了日志,而且打印了logger的className,竟然从org.slf4j.Logger变成了 class ch.qos.logback.classic.Logger。

原因暂时不说,在slf4j里面讲。

现在你还有更需要注意的事情!

请把代码里的logger.info改为logger.debug,再次运行。

你会发现日志还是打印了。如果你了解一些关于日志级别的有关信息,那么你应该知道本例中的logger的级别就是DEBUG级别,否则打印不出来。

原因在于:logback会先去寻找配置文件logback-test.xmllogback.xml,如果没有找到,则会使用ch.qos.logback.core.ConsoleAppender这个默认的控制台输出配置。而logback的根记录器的级别默认是DEBUG。

如果你遇到过控制台debug日志无脑刷出,什么都控制不了,那么原因就在于此。那么请配置一个logback.xml来修改格式或者级别即可。一个简单的info级别的logback.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
    debug="false" scan="true" scanPeriod="30 second">
    
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    	<encoder charset="utf-8">
           <pattern>%n%-6p %m %n</pattern>
        </encoder>
    </appender>    
    <root level="INFO">
       <appender-ref ref="STDOUT" />
    </root>
 </configuration>

Nop

Nop就是静默处理,就是什么都不干。爱咋咋滴,也不打印也不输出。

你可以找任意一款NopLogger.java的源码,就会发现它里面都是空的。

Nop的作用是什么?在slf4j里说。

slf4j

重头戏到了。

slf4j是简单日志门面,它不提供具体的实现,只是它有和其他日志之间的连接器,姑且就叫做连接器吧。如下图:

先不看JCL.先看蓝色和绿色。

slf4j如果底层使用javaLog,需要slf4-jdk.jar

slf4如果底层使用log4j,需要使用slf4-log4j.jar

slf4如果底层使用logback,需要使用logback-classic.jar

而slf4j的核心jar包是slf4j - api.jar。

那么如果你想使用slf4j,请先导入slf4j - api.jar,然后选择其中一个底层日志系统,引入其包以及连接器的jar包。接着如下使用即可。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogBackLog {
	public static void main(String[] args) {
		Logger logger = LoggerFactory.getLogger(LogBackLog.class);
		logger.info("aaaaaaaa");
		System.out.println(logger.getClass());
	}
}

这个代码片和上面讲logback的代码片一摸一样。这就是接口的魅力,如果你想更换底层日志系统,只需要更换底层日志包和连接器包即可。

自动搜寻底层日志系统的原理就是:其实每一个连接器里都有一个org.slf4j.impl.StaticLoggerBinder这个类,是相同的包相同的类哦。slf4j会自动搜索类路径下的org.slf4j.impl.StaticLoggerBinder,如果搜到了某个org.slf4j.impl.StaticLoggerBinder,就加载该StaticLoggerBinder所处的连接器,使用该连接器里所默认的底层日志系统。

注意以下几点:

1.如果你只引入了slf4j - api.jar,而不引入底层实现或连接器,那么运行上面的代码将不会打印日志,而log.getClass的结果是NopLogger,Nop作用就是这样,既然我不知道咋办,那我就啥都不干。

2.如果你更换了底层实现或连接器,那么logger,getClass将会改变,因为具体实现已经改变。

3.如果你更换成了log4j或者logback,请附带上她们的log4j.properties或logback.xml。

4.如果你引入了多种底层实现或连接器,那个现象,呵呵了~~~~~~解释一下,slf4j是严格不推荐你这样做的,但是现在的系统都有各种依赖,而依赖里的日志系统又不尽相同,所以有时我们也没有办法。该怎么做呢?请看问答

jcl

指的是org.apache.common-logging.jar包。

是apache早期的项目,2000年左右的时候就有了,期间也更新过几次。

它也是个日志的门面系统,同样的也有连接器,但最重要的是它的配置文件,说到这里,有同学可能会奇怪,为什么我一直在用common-logging.jar,而不需要配置文件,却能照样打印使用啊?

说来话长,请看jcl目前的搜索底层日志实现的执行流程,以下流程,顺序执行,如果匹配,则立即终止:

1.查找配置文件commons-logging.properties。如果有,看里面配置了什么底层实现。

2.查找System.getProperties("org.apache.commons.logging.LogFactory"),如果不是null,看结果代表了什么底层实现.

3.查找所有jar包的注册信息,如果里面有META-INF/services/org.apache.commons.logging.LogFactory这个文件,读取该文件的第一行即是配置了底层实现.

4.如果有log4j.jar.则设置为log4j为底层实现

5.如果是java1.4以后,则设置为javaLog

6.使用自带的默认的SimpleLog

而我们平时使用jcl一般都是配合Log4j使用,都是到了第四步终止。

而且即使没有log4j,还有第五步使用javaLog呢!所以使用JCL时完全不用担心的。

第三步则是jcl连接器的事情,如果有连接器,那么log4j就没有用了。

问答:

1.如果slf4j里引入了多种连接器和底层实现.那么真正执行的是谁?

我只知道现象,哪个连接器先加载,就执行谁.因为slf4j搜索连接器会搜索所有的连接器,然后放到一个数组里.但是好像默认取数组[0]作为真正的日志实现.

2.项目日志包只加载这些,且没有配置文件,请问Spring的debug运行日志会显示出来吗?底层实现是哪个日志系统?

slf4j - api.jar,

common-logging.jar,

log4j.jar,

logback-core.jar,

logback-classic.jar,

jcl-over-slf4j.jar

debug日志会显示出来,底层是logback

原因是:spring使用jcl作为日志门面,jcl会按照搜索顺序,在第三步停止,因为jcl-over-slf4j.jar是将slfj作为jcl的底层实现d的连接器,而slf4j启动起来也会搜索真正的底层实现,所以最终只搜到了logback的连接器(缺少log4到slf4j的连接器)。而logback.xml没有配置出来,所以会使用默认的控制台打印且默认级别是debug.

实际上就有了一种桥接的作用.

3.我们讲slf4j时那个连接器图里,还有个slf4j-jcl的连接器的jar,那个是将jcl作为slfj的底层实现的连接器,和jcl-over-slf4j.jar作用正好相反,如果将该jar投入到第二题环境里面。然后将logback-classic.jar删除掉,则会发生什么事情?会不会发生slf4j和jcl循环调用最终导致栈溢出呢?

自己去试试吧!

4.有些依赖源码里直接使用的log4j,而我现在希望由slf4j+logback来控制所有的日志怎么办?

jcl-over-slf4j.jar是jcl桥接到slf4j的.

log4j-over-slf4j.jar是log4j桥接到Slf4j里面的.

当然也有javaLog桥接到Slf4里面的.

切记使用这种模式的时候,小心自循环调用.

最优使用

强烈推荐slf4j作为门面,然后使用logback作为底层实现,因为logback十分高效,当然你可以随时切换底层实现。

由于一些依赖使用了jcl,那么请添加jcl-over-slf4j.jar,将jcl的日志系统实际上由slf4j把控。

结语:

写作原因是因为自己的项目里引入多种依赖,导致日志系统各种灵异事件,网上教程,也都是读起来无味之极,索性便花了两天略读源码,又去官网看文档,大抵才了解一些。

写了4个半小时,酣畅淋漓。

煎炒烹炸,盛盘出来,以飨诸君。

发布了514 篇原创文章 · 获赞 182 · 访问量 36万+

猜你喜欢

转载自blog.csdn.net/dmw412724/article/details/84190883