SLF4j:Log facade abstract
内 容:
- 应用中使用slf4j的工作流程
- 简单示例
- ILoggerFactory实例化过程
- 由ILoggerFactory创建Logger实例
- slf4j 适配器实现
- 自定义适配器
- slf4j 如何选取多个Log框架
- 如何将commons-logging项目迁移到SLF4j
现如今,日志框架层出不穷,JDKLogger、Log4j、Logback等这些是最常用的了。然而现在越来越多的框架中,都会在使用日志框架的同时,还会使用到一个门面(slf4j-api.jar),使用这个门面的的最方便的地方大抵是它提供格式化字符串的功能。
slf4j 与其他日志框架的关系
在应用程序中,直接使用slf4j-api.jar就可以完成日志的记录,而不用在代码里直接使用某一种日志框架了(虽然最终记录日志还是有日志框架来完成的)。
下面是使用了slf4j时,应用程序、slf4j、slf4j-adapter.jar、日志框架之间的调用关系:
下面是一个简单的示例:
package com.fjn.frame.slf4j; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class HelloWorld { public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info("Hello World");
}
}
LoggerFactory.getLogger(xxx)要分为两个过程:
1、实例化ILoggerFactory, 这个步骤只是在第一次进行。
2、根据ILoggerFactory实例创建Logger实例。
下面就分别来说说这两个过程:
ILoggerFactory 实例化的过程
在使用slf4j时,并不需要指定具体使用哪种日志框架,只需要给定相关的适配器包就可以了。那么如何拿到真正的ILoggerFactory实现,并实例化的呢?
1、在LogFactory的classloader的搜索路径下查找 ” org/slf4j/impl/StaticLoggerBinder.class” 类
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; private static void singleImplementationSanityCheck() {
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class
.getClassLoader();
Enumeration paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader
.getResources(STATIC_LOGGER_BINDER_PATH);
}
// use Set instead of list in order to deal with bug #138
// LinkedHashSet appropriate here because it preserves insertion order during iteration
Set implementationSet = new LinkedHashSet();
while (paths.hasMoreElements()) {
URL path = (URL) paths.nextElement();
implementationSet.add(path);
}
if (implementationSet.size() > 1) {
Util.report("Class path contains multiple SLF4J bindings.");
Iterator iterator = implementationSet.iterator();
while(iterator.hasNext()) {
URL path = (URL) iterator.next();
Util.report("Found binding in [" + path + "]");
}
Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
}
如果有多个就会打印:
2、将slf4j与指定的实现进行绑定,这一步的操作,通常是:
1)单实例化StaticLoggerBinder。
2)检查StaticLoggerBinder的版本,其实就是需要有一个静态的非final的变量(这个变量不是必须得有的),
StaticLoggerBinder.REQUESTED_API_VERSION
3、获取到ILoggerFactory的实例
一般来说,是返回一个static ILoggerFactory impl=new XXXLoggerFactory();
由ILoggerFactory来创建Logger实例
LoggerFactory创建Logger实例,其实由日志框架本身的LogManager创建一个Logger,然后包装成LoggerAdapter。例如Log4j的适配包中的Log4jLoggerFactory#getLogger(String name)的实现如下:
public Logger getLogger(String name) {
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
org.apache.log4j.Logger log4jLogger;
if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
log4jLogger = LogManager.getLogger(name); Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
下面用是一张简易的关系图,显示了适配器的实现:
自定义日志框架适配器
在一些公司,肯定还有自己的Logger框架,如果也希望通过slf4j来做日志,就需要写相关的适配器包了。通过上述的两个过程的了解,很容易就能知道如何自定义适配器了。
自定义适配器中,必须包括3个组件:
· StaticLoggerBinder
这个类需要遵守下列规约:
1) 类名必须是org.slf4j.impl.StaticLoggerBinder
2) 这个类必须是单例的,必须有getSingleton()方法
3) 尽可能的有 public static String REQUESTED_API_VERSION 字段,并且不能是final的。
4) 要实现org.slf4j.spi.LoggerFactoryBinder接口。
· LoggerFactoryImpl
这个类要实现org.slf4j.ILoggerFactory接口
· LoggerAdapter
这个类要实现org.slf4j.Logger接口。
如何选取多个Log框架
SLF4j原则上只会绑定一个适配器,所以通常我们的项目中,最好只使用一种日志框架。然而事与愿违,现在项目中通常都会引入大量第三方框架等,这些框架使用的日志框架又不尽相同,所以引入多个日志框架的情况也是不可避免的。SLF4j初始化时,如果找到了多个相关的适配器,只会使用找到的第一个适配器。
在项目中要尽量减少引入的log框架的数量,通常会使用maven exclusion:
<dependencies>
<dependency>
<groupId> org.apache.cassandra</groupId>
<artifactId>cassandra-all</artifactId>
<version>0.8.1</version> <exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions> </dependency>
</dependencies>
如何将项目从Commons-Logging迁移到SLF4j
如果项目中(或者引入的第三方jar中)已经使用了commons-logging,要迁移至SLF4j。
需要做两个事:
1、将项目中已使用commons-logging的模块、以及第三方jar。使用maven exclustions排除掉。
2、引入jcl-over-slf4j.jar。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
原因:
项目(或者第三方jar)中使用的是commons-logging的API:org.apache.commons.logging.Log、org.apache.commons.logging.LogFactory。
这两个类在jcl-over-slf4j.jar中都有。不过修改了其实现。
在修改后的org.apache.commons.logging.LogFactory的实现是将原来的LogFactory查找过程完全替换成了jcl-over-slf4j.jar包中的一个SLF4jLogFactory:
package org.apache.commons.logging; import java.util.Hashtable; import org.apache.commons.logging.impl.SLF4JLogFactory; /**
* <p>
* Factory for creating {@link Log} instances, which always delegates to an
* instance of {@link SLF4JLogFactory}.
*
* </p>
*
* @author Craig R. McClanahan
* @author Costin Manolache
* @author Richard A. Sitze
* @author Ceki Gülcü
*/ public abstract class LogFactory { static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J = "http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j"; static LogFactory logFactory = new SLF4JLogFactory(); public static LogFactory getFactory() throws LogConfigurationException {
return logFactory;
} ...
... }
而SLF4jLogFactory的实现是委托给slf4j的LoggerFactory去定位日志框架并取得Logger对象,最后将取得的Logger对象再包装成commons-logging中的Log实现:
public class SLF4JLogFactory extends LogFactory {
... public Log getInstance(String name) throws LogConfigurationException {
Log instance = loggerMap.get(name);
if (instance != null) {
return instance;
} else {
Log newInstance;
Logger slf4jLogger = LoggerFactory.getLogger(name); // 又委托给了Slf4j的 LoggerFactory
if (slf4jLogger instanceof LocationAwareLogger) {
newInstance = new SLF4JLocationAwareLog((LocationAwareLogger) slf4jLogger);
} else {
newInstance = new SLF4JLog(slf4jLogger);
}
Log oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
} }
所以迁移时,一定要完全排除commons-logging的jar,并引入 jcl-over-slf4j.jar
SLF4j:Log facade abstract的更多相关文章
- slf4j(simple logging facade for java)
http://www.tuicool.com/articles/IfeUfq slf4j(simple logging facade for java)是Java的简单的日志门面,它 不是具体的日 ...
- 转:Java中abstract和interface的区别
转自:Java中abstract和interface的区别 abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java ...
- Golang 源码剖析:log 标准库
Golang 源码剖析:log 标准库 原文地址:Golang 源码剖析:log 标准库 日志 输出 2018/09/28 20:03:08 EDDYCJY Blog... 构成 [日期]<空格 ...
- 学习:Log中'main', 'system', 'radio', 'events'
在Android中不同的log写到不同的设备中,共有/dev/log/system, /dev/log/main, /dev/log/radion, /dev/log/events四中类型.其中默认L ...
- 转:Log Explorer使用说明恢复被误删除的数据
一.介绍 Log Explorer主要用于对MSSQLServer的事物分析和数据恢复.你可以浏览日志.导出数据.恢复被修改或者删除的数据(包括执行过update,delete,drop和trunca ...
- IIS 日志分析工具:Log Parser Studio
1.安装Log Parser,下载地址:http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=24659 ...
- 复分析可视化方法:笔记:log(z)的可视化微分法
当z转过θ时,我们来看看发生了什么: 左图中的空心箭头代表z的变化量,其长度为rδ,方向为pi/2+θ: 右图中的实心箭头代表log(z)的变化量,其长度为δ,方向为pi/2. 因此,从左图空心箭头到 ...
- web 安全相关(一):Log注入(转)
在网上有很多关于安全的文章,但是 OWASP 开发指导 涵 盖了几乎所有关于Web站点安全的东西.(注:OWASP(开放Web应用安全项目- Open Web Application Security ...
- 面试题思考:interface和abstract的区别
抽象类(abstract) 含有abstract修饰符的class即为抽象类,abstract 类不能创建的实例对象. 含有abstract方法的类必须定义为abstract class,abstra ...
随机推荐
- iOS开发——高级特性&Runtime运行时特性详解
Runtime运行时特性详解 本文详细整理了 Cocoa 的 Runtime 系统的知识,它使得 Objective-C 如虎添翼,具备了灵活的动态特性,使这门古老的语言焕发生机.主要内容如下: 引言 ...
- 【iOS】NSNumberFormatter
介绍 NSNumberFormatter 应该可以满足你对数据形式的一般需求,值得了解一下. NSNumber *num1 = [NSNumber numberWithDouble:1234567.8 ...
- Callbacks vs Events
前言:本文翻译自Dean Edwards的一篇文章,原文地址:http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/. 文章主要指出了 ...
- Color Transfer between Images code实现
上计算机视觉课老师布置的作业实现论文:Color Transfer between Images 基本思路是: 1.给定srcImg和targetImg 2.将RGB空间转为Lab空间 3.根据论文中 ...
- JavaWeb路径问题打包总结--小心出门右转404
话说,培训和自学就不是一个回事,两周讲完java基础,两天讲完jsp,两节课讲完servlet,还真不是一般人能受得了的,这两天学习jsp和servlet频繁被路径问题困扰,倒不是出错,只是各种act ...
- java读写file
private static String encoding = "utf-8"; public static void readTxt(String filePath) thro ...
- MVC中路由
篇目 介绍 路线的性质 了解缺省路由 用一个例子的路由 结论 介绍 本文介绍了MVC中的路由.如何执行的路线是由路由引擎和如何定义的URL路由. ASP.NET MVC的路由是一个模式匹配系统,负责传 ...
- WebAPI2使用AutoFac依赖注入完整解决方案。
WebApi2上进行依赖注入,在百度里能搜到的的完整解决方案的文章少之又少,缺胳膊断腿. 和MVC5依赖注入的不同之处,并且需要注意的地方,标记在注释当中.上Global代码: namespace S ...
- html5手机端的点击弹出侧边滑动菜单代码
效果预览:http://hovertree.com/texiao/html5/19/ 本效果适用于移动设备,可以使用手机等浏览效果. 源码下载:http://hovertree.com/h/bjaf/ ...
- 绿色简单的学校登录html页面
效果预览:http://hovertree.com/texiao/css/22/ 代码如下: <!DOCTYPE html> <html> <head> <m ...