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等桥接包 。

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

利用日志工厂获取到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替换掉就好了,看下图:

具体的原理是什么呢? 以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 等。
java的日志知识的更多相关文章
- 【Java】日志知识总结和经常使用组合配置(commons-logging,log4j,slf4j,logback)
Log4j Apache的一个开放源码项目,通过使用Log4j,我们能够控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Syslog守护进程等.用 ...
- JAVA主流日志梳理
JAVA主流日志梳理 引入 历史故事 Log4j - JDK1.3及以前 JUL - JDK1.4 JCL - 日志门面commons-logging的出现 SLF4j - 可能是最好的日志框架 lo ...
- 探索Java的日志世界
探索Java的日志世界 本文的思维导图 一.主题 打开日志的大门,探索的Java日志世界 二.目标 了解常用的日志框架 掌握日志框架的选择和使用以及开发规范 了解日志框架中的一些设计思想 三.内容 1 ...
- 细说Java主流日志工具库
概述 在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息. 在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子. 我们先来逐一了解一下主流日志工具. java.util ...
- Java主流日志工具库
在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息.在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子.我们先来逐一了解一下主流日志工具. 1.java.util.lo ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java 标准日志工具 Log4j 的使用(附源代码)
源代码下载 Log4j 是事实上的 Java 标准日志工具.会不会用 Log4j 在一定程度上可以说是衡量一个开发人员是否是一位合格的 Java 程序员的标准.如果你是一名 Java 程序员,如果你还 ...
- Java面试必备知识
JAVA面试必备知识 第一,谈谈final, finally, finalize的区别. 第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可 ...
- Java自定义日志输出文件
Java自定义日志输出文件 日志的打印,在程序中是必不可少的,如果需要将不同的日志打印到不同的地方,则需要定义不同的Appender,然后定义每一个Appender的日志级别.打印形式和日志的输出路径 ...
随机推荐
- 【FJOI2016】建筑师
安利另外一篇\(blog\) 密码泥萌都知道 题面 题解 为了描述方便,这里将建筑称作\(zsy\) 高度为\(n\)的\(zsy\)无论如何都能从左右两侧看到.剩下的部分,从左边看到的是前缀\(ma ...
- burp抓取手机包
burp监听ip和端口要填对应的使用的ip,比如建立了一个网卡wifi,那就填那个ip 手机代理连接wifi的话,就直接先看能不能访问burp监听的端口,然后填上相同代理即可.
- SpringBoot日记——SpringMvc自动配置与扩展篇
为了让SpringBoot保持对SpringMVC的全面支持和扩展,而且还要维持SpringBoot不写xml配置的优势,我们需要添加一些简单的配置类即可实现: 通常我们使用的最多的注解是: @Bea ...
- 通过ftp同步服务器文件:遍历文件夹所有文件(含子文件夹、进度条);简单http同步服务器文件实例
该代码主要实现,指定ftp服务地址,遍历下载该地址下所有文件(含子文件夹下文件),并提供进度条显示:另外附带有通过http地址方式获取服务器文件的简单实例 废话不多说,直接上代码: 1.FTPHelp ...
- 一切的浮点型进行计算操作都要用BigDecimal
简化: 1.引言 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确 ...
- [硬件配置]Ubuntu 16.04下使用NETGEAR Nighthawk AC1900 (A7000) WIFi USB适配器
为了增强无人机与地面站之间的传输信号,组里买了这款WiFi信号接收器,无奈只有Windows和Mac OS版本的驱动程序.后来不知道从哪里得来的一个偏方可以安装Ubuntu下的驱动,特此记录. 内核降 ...
- python魔法方法大全
1.python魔法方法详解: python魔法方法是可以修改重载的,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而 ...
- SSL详解
SSL 1.整体结构 SSL是一个介于HTTP协议与TCP之间的一个可选层,其位置大致如下 SSL:(Secure Socket Layer,安全套接字层),为Netscape所研发,用以保障在Int ...
- oracle 数据库的详细安装教程
由于oracle数据库比较大 所以安装的时候比较慢是目前装的最大的软件了吧 而且如果装崩了 可能还会重装系统 不过比较幸运 一次就装好 1.需要去官网下载 https://www.oracle.co ...
- python-gevent模块实现socket大并发
服务器端:gevent_server.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...