java 日志是什么_java的日志知识

java常用的日志有以下几种 :

一、jdk自带的java.util.logging包下的日志功能, 不常用。

二、commons-logging  + log4j 的搭配 。log4j是日志功能的具体实现,而commons-logging则是日志接口的声明,它的出现也是为了解决应用和具体的日志框架解耦合的问题,它采用的是运行时动态绑定的方式来决定使用哪个日志框架。什么是动态绑定 ?参考commons-logging-1.1.3的org.apache.commons.logging.LogFactory类的方法:

public static Log getLog(Class clazz) throws LogConfigurationException {

return getFactory().getInstance(clazz);

}

关键在getFactory()返回的LogFactory(日志工厂) 是什么 !

我们进一步看获取日志工厂的方法:

public static LogFactory getFactory() throws LogConfigurationException

从419-646行:代码比较长不列出,阐述如下:

1、获取线程上下文ClassLoader(默认是加载应用的ClassLoader)。

2、看线程上下文ClassLoader是否有缓存的LogFactory,有就直接返回LogFactory  。

3、找classpath下面的commons-logging.properties ,如果use_tccl属性为false,则不使用Thread ContextClassLoader .默认use_tccl 为true ;.

4、找是否有org.apache.commons.logging.LogFactory 这个系统配置项,利用Thread ContextClassLoader 加载org.apache.commons.logging.LogFactory ,并创建一个LogFactory实例(在后面要描述的jcl-over-slf4j包和commons-logging包里面都有这个类。)

5、如果还找不到,则找包含了META-INF/services/org.apache.commons.logging.LogFactory 这个文件的Jar包,找到了就用这个文件里面的LogFactory类名创建LogFactory实例

6、如果还找不到,则找commons-logging.properties 文件,利用属性文件里面的org.apache.commons.logging.LogFactory 属性获取LogFactory类并创建LogFactory实例。

7、还找不到,则找org.apache.commons.logging.impl.LogFactoryImpl 这个类 创建实例。

8、创建好LogFactory实例以后,会

cacheFactory(contextClassLoader, factory);

把LogFactory对象和线程上下文ClassLoader在map中关联起来,加速LogFactory对象的获取。

从以上的分析来看,我们假设一种简单的场景,

没有org.apache.commons.logging.LogFactory 这个系统配置项,classpath下没有包含META-INF/services/org.apache.commons.logging.LogFactory 这个文件的Jar包、没有commons-logging.properties 文件,只有commons-logging和Log4j的jar .

此时会使用org.apache.commons.logging.impl.LogFactoryImpl 这个类(在commons-logging的jar 包里面) 来创建Log实例,而LogFactoryImpl在获取Log类的时候,会参照下面一个顺序:

private static final String[] classesToDiscover = {

LOGGING_IMPL_LOG4J_LOGGER,

"org.apache.commons.logging.impl.Jdk14Logger",

"org.apache.commons.logging.impl.Jdk13LumberjackLogger",

"org.apache.commons.logging.impl.SimpleLog"

};

来使用某一个日志器, 可以看到默认就是使用log4j日志的。

至此,我们弄清了commons-logging的动态绑定机制。

但是这种机制的问题在哪儿呢,由于它使用了ClassLoader寻找和载入底层的日志库, 导致了象OSGI这样的框架无法正常工作,因为OSGI的不同的插件使用自己的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging无法工作。

三、slf4j + logback的搭配.

slf4j和logback是同一个人开发的,所以不像slf4j + log4j搭配使用时,还需要加上一个所谓的适配器jar包(比如:slf4j-log4j.jar,适配器包的作用就是通过class composition的适配方式把log4j的日志转换成slf4j的接口)。

和commons-logging在运行时确定日志框架不同,slf4j采用的方式是在编译时静态绑定真正的log库, 它的原理是:

(1)用ClassLoader找包含了org.slf4j.impl.StaticLoggerBinder类的Jar包,这个Jar就包含在logback-classic.jar、slf4j-log4j等包里面 ,因此,如果在classpath下面

同时包含了这些jar的话, 程序将会出现一个警告,提示classpath下面有多个slf4j的绑定 。这也是我们在使用slf4j日志时需要注意的问题,不过slf4j并不会报错, 而是选择一个

jar中的StaticLoggerBinder,所以在使用的时候要特别注意不能同时包含logback-classic 、 slf4j-log4j、slf4j-jdk等桥接包 。

735d78638a5d743eb795f140aa825a67.png

我们假设使用的是logback做日志框架 ,这时会拿到logback-classic.jar里面的org.slf4j.impl.StaticLoggerBinder ,这个StaticLoggerBinder获取到日志工厂以后,

2289ee0228c69d8bb30e4a435e6ad965.png

利用日志工厂获取到ch.qos.logback.classic.Logger, 接下来使用的就是logback的日志了。

而如果是classpath下面包含的是slf4j-log4j这个桥接包, 那么拿到的就是Log4j的LogFactory,从而也就用到了log4j的日志。

四、既然slf4j的静态绑定方式解决了commons-logging动态绑定方式在运行时可能拿不到日志接口实现类的问题,而且号称效率比log4j要更好(为什么更好,后续还会深入分析) 那直接都换成slf4j+logback的日志方式不就行了么,但现实是很多的应用之前都是建立在commons-logging+log4j的日志方式上的,有什么办法不改动应用的代码,达到commons-logging日志转到slf4j的目的么?把commons-logging.jar替换掉就好了,看下图:

0eb1f143f54a30807d4c3811afa6d0a4.png

具体的原理是什么呢? 以LogFactory.getLog("loggerName")为例:

1、org.apache.commons.logging.LogFactory类被jcl-over-slf4j包里面的同包同名类替换掉了。

2、获取到的日志工厂是一个SLF4jLogFactory ,这个日志工厂在获取org.apache.commons.logging.Log 实例的时候,先基于前面描述的slf4j静态绑定机制,拿到了一个org.slf4j.Logger,然后用一个适配器类做接口转换,把slf4j的日志转换成commons-logging的日志器。

总结下来,我们有以下几点启发:

1、适配器模式可以帮助我们做各种接口包的无缝集成。

2、复杂的java应用还是在classloader机制上做文章,即使是slf4j的静态绑定机制 ,其实也是在编译时检查了classpath下是否有多个jar包包含StaticLoggerBinder类,

真正运行的时候由线程上下文的classloader(默认是app classloader)来加载这个StaticLoggerBinder类而已。

3、要分清Java日志系统里面各种包的作用:

1)日志接口包:commons-logging , slf4j-api

2) 日志框架包:log4j, logback,

3)  日志适配器包:slf4j-log4j,slf4j-jdk

4)  把某一个日志接口转换到另一个日志接口的桥接包:jcl-over-slf4j,log4j-over-slf4j 等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值