文档章节

Java日志那点儿事儿

路小磊
 路小磊
发布于 2015/12/11 21:07
字数 1650
阅读 848
收藏 21

##前言

日志这东西在语言里算基础组件了吧,可惜Java界第三方框架向来比原生组件好用也是事实,缺点是框架太多混战江湖,今天我们就理一理这些日志框架。Java的日志框架分为门面(Facade),或者叫通用日志接口,还有日志实现。日志接口不用说,就是定下的日志方法规范,需要具体日志组件去实现的(为啥Sun当年没有定义这东西,看看JPA、JDBC、JMS这些规范定义的多好,或者定义了被抛弃了?)。日志实现就是具体的日志组件了,可以实现日志打印到控制台、文件、数据库等等。下面咱们就具体说说这些东西。

Java日志框架分类

日志门面(Facade)

  • Slf4j

全称Simple Logging Facade for JAVA,真正的日志门面,只提供接口方法,当配合特定的日志实现时,需要引入相应的桥接包

  • Common-logging

Apache提供的一个通用的日志接口,common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库,自己也自带一个功能很弱的日志实现。

差别:

  1. Common-logging动态查找日志实现(程序运行时找出日志实现),Slf4j则是静态绑定(编译时找到实现),动态绑定因为依赖ClassLoader寻找和载入日志实现,因此类似于OSGI那种使用独立ClassLoader就会造成无法使用的情况。(呵呵,我一个插件用一个日志框架不行啊,土豪多任性,不过说实话,没用过OSGI,这个我还真没有概念)
  2. Slf4j支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。

日志实现

  • Log4j

Log4j可能是Java世界里最出名的日志框架了,支持各种目的地各种级别的日志输出,从我刚接触日志就知道这个框架(呵呵,我一直不知道还有JDK Logging这个东西)。最近(也不近了……)Log4j2发布正式版了,没看到谁用,听说也很不错。

  • LogBack

Log4j作者的又一力作(听说是受不了收费文档搞了个开源的,不需要桥接包完美适配Slf4j),个人感觉迄今为止最棒的日志框架了,一直都在用,配置文件够简洁,性能足够好(估计是看自己的Log4j代码差劲了,更新不能解决问题,直接重构了)。

  • JDK Logging 从JDK1.4开始引入,不得不说,你去Google下这个JDK自带的日志组件,并不如Log4j和LogBack之类好用,木有配置文件,日志级别不好理解,想顺心的用估计还得自己封装下,总之大家已经被Log4j惯坏了,JDK的设计并不能被大家认同,唯一的优点我想就是不用引入新额jar包了。

为什么会有门面

看了以上介绍,如果你不是混迹(深陷)Java多年的老手,估计会蒙圈儿了吧,那你肯定会问,要门面干嘛。有了手机就有手机壳、手机膜,框架也一样,门面的作用更多的还是三个字:解耦合。说白了,加入一个项目用了一个日志框架,想换咋整啊?那就一行一行的找日志改呗,想想都是噩梦。于是,门面出来了,门面说啦, 你用我的格式写日志,把日志想写哪儿写哪儿,例如Slf4j-api加上后,想换日志框架,直接把桥接包一换就行。方便极了。

说实话,现在Slf4j基本可以是Java日志的一个标准了,按照它写基本可以实现所有日志实现通吃,但是就有人不服,还写了门面的门面(没错,这个人就是我)。

门面的门面

如果你看过Netty的源码,推荐你看下io.netty.util.internal.logging这个包里内容,会发现Netty又对日志封装了一层,于是灵感来源于此,我也对各大日志框架和门面做了封装。

Hutool-log模块

无论是Netty的日志模块还是我的Hutool-log模块,思想类似于Common Logging,做动态日志实现查找,然后找到相应的日志实现来写入日志,核心代码如下:

/**

 * 决定日志实现

 * @return 日志实现类

 */
public static Class<? extends AbstractLog> detectLog(){
	List<Class<? extends AbstractLog>> logClassList = Arrays.asList(
			Slf4jLog.class,
			Log4jLog.class, 
			Log4j2Log.class, 
			ApacheCommonsLog.class, 
			JdkLog.class
	);
	
	for (Class<? extends AbstractLog> clazz : logClassList) {
		try {
			clazz.getConstructor(Class.class).newInstance(LogFactory.class).info("Use Log Framework: [{}]", clazz.getSimpleName());
			return clazz;
		} catch (Error | Exception e) {
			continue;
		}
	}
	return JdkLog.class;
}

详细代码可以看这里

说白了非常简单,按顺序实例化相应的日志实现,如果实例化失败(一般是ClassNotFoundException),说明jar不存在,那实例化下一个,通过不停的尝试,最终如果没有引入日志框架,那使用JDK Logging(这个肯定会有的),当然这种方式也和Common-logging存在类似问题,不过不用到跨ClassLoader还是很好用的。

对于JDK Logging,我也做了一些适配,使之可以与Slf4j的日志级别做对应,这样就将各个日志框架差异化降到最小。另一方面,如果你看过我的这篇日志,那你一定了解了我的类名自动识别功能,这样大家在复制类名的时候,就不用修改日志的那一行代码了,在所有类中,日志的初始化只有这一句:

Log log = LogFactory.get();

是不是简洁简洁又简洁?实现方式也很简单:

/**
 * @return 获得调用者的日志
 */
public static Log get() {
	return getLog(new Exception().getStackTrace()[1].getClassName());
}

通过堆栈引用获得当前类名。

作为一个强迫症患者,日志接口我也会定义的非常处女座:

/**
 * 日志统一接口
 * 
 * @author Looly
 *
 */
public interface Log extends TraceLog, DebugLog, InfoLog, WarnLog, ErrorLog

这样就实现了单一使用,各个日志框架灵活引用的作用了。好了,今天就到这里了,有问题或者吐槽都已给我留言~~

© 著作权归作者所有

路小磊

路小磊

粉丝 433
博文 55
码字总数 42397
作品 5
呼和浩特
程序员
私信 提问
加载中

评论(7)

剑神卓不凡
剑神卓不凡
本人还不服
紫泉-kwer
紫泉-kwer
眼前一亮 非常感谢
金贞花
金贞花

引用来自“路小磊”的评论

引用来自“开源中国大Boss”的评论

qq

做个备注
路小磊
路小磊 博主

引用来自“开源中国大Boss”的评论

qq

金贞花
金贞花
qq
路小磊
路小磊 博主

引用来自“汪林”的评论

1379
汪林
汪林
1379
一年外企经历,求上海Android应用开发职位。

附上Git简历:https://gist.github.com/ryanhoo/5227540 普通应届生,魔都某二本电商专业。时年22,为人略天真略二,风华正茂,玉树临风(是真的 ;-) )。 放人堆里应酬P都不愿意弹一个,说起...

RyanHoo
2013/03/23
677
4
java.lang.OutOfMemoryError: Java heap space

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 今天我想说说这个有趣的问题,这的确是个让人费解的是error 问题来源: 这个问题一般会出在myecplise 和ecplise ,...

soul_mate
2014/05/03
366
0
5年时间,Java程序员如何从小白晋升为大牛

程序员之言 2018-06-25 在程序界流行着一种默认的说法叫“黄金5年”,也就是一个程序员从入职的时候算起,前五年的选择直接影响着整个职业生涯中的职业发展方向和薪资走向。 因此如何走好这5...

ydx20151111
2018/06/25
0
0
毕业设计记录(一)配置web开发环境(java)

本打算跟着总结,写好日志。但是真正忙的时候没有时间总结,有空时又爱玩,只能抽空总结。今天是毕业设计做了一小部分,不知道下一阶段咋整了,所以总结。 首先毕业设计做的事web应用,用的j...

jiler
2014/05/08
258
0
【时速云线上分享】第九期:镜像构建优化之路

为促进Docker、Kubernetes等技术的交流传播,同时帮助用户更全面地了解时速云产品及其应用,时速云每两周会进行一次技术分享,分享时间为周四晚8:30-9:30在用户微信群、时速云技术分享群等进...

时速云
2016/06/01
200
0

没有更多内容

加载失败,请刷新页面

加载更多

3 汇编的函数调用

3 汇编的函数调用 3.1 无参数和返回值的函数调用 void func_void(){ printf("func, no param, no return value\n");}// func_void();asm ("call func_void"); // call指令调......

风从东方来
今天
59
0
AQS讲的很好,很透彻的一篇

JUC AQS ReentrantLock源码分析(一) https://blog.csdn.net/java_lyvee/article/details/98966684

南桥北木
昨天
49
0
0219 springmvc-拦截器和响应增强

拦截器 拦截器分同步拦截器和异步拦截器; HandlerInterceptor 方法和执行时机 可以看DispathcerServlet的原来确定它的三个方法的执行时机; AsynHandlerInterceptor 看注释,主要用来清理在...

李福春carter
昨天
44
0
返沪第一天,学习不能断,工作还要继续

返沪第一天 今天是2020年02月19日,是我返沪第一天,早上的体温是36.5,晚上的体温为36.6. 呵呵 -- 正常 说起返沪,海囧有木有。 回沪需要多转(转车三次) 从家开车到高铁站(这可是我第一次...

lihua20103181
昨天
82
0
Golang并发编程之互斥锁、读写锁详解

[TOC] Golang并发编程之互斥锁、读写锁详解 谢谢慕课网cap1537老师,写的不错. 我们对Go语言所提供的与锁有关的API进行说明。这包括了互斥锁和读写锁。我们在第6章描述过互斥锁,但却没有提到...

我爱吃炒鸡
昨天
48
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部