1 log4j
log4j是使用得最广泛的日志系统,log4j对日志系统抽象出logger,logger工厂,appender,日志级别,日志格式等核心概念。这几个概念被广泛借鉴于其他日志系统的设计,经久不衰。
它的核心类图如下:
在上图中最重要的一个类是Logger,客户直接调用这个类打出各种级别的日志。logger是一个层级结构,可能有父logger和子logger,这种层级关系的意义在于可以使子logger继承父logger的某些属性,或者可以让父logger的日志信息涵盖子logger。
logger组合了一个AppenderAttachableImpl,AppenderAttachableImpl聚合了一组appender(即日志输出源)。appender的日志级别、日志文件路径、日志文件行为、日志格式都可以通过log4j.xml文件配置。
2 simple log facade for java(SLF4J)
在java的开源体系内,除了log4j之外,还有很多其他的日志系统如jdk自带的util包里的logging、logback(log4j的作者吸取了log4j的经验,最新开发出来的另一个日志系统,据说性能更优越)等。
为了方便应用能够在不改变代码的前提下灵活改变日志系统的实现,比如想从log4j迁移到logback里,SLF4J对所有日志系统进行更高层次的抽象,为不同的日志系统提供了统一的门面,客户代码只需要和SLF4J打交道,调用门面统一接口就能做到和具体的日志系统解耦,可以在部署时切换不同的日志系统实现。
客户调用LoggerFactory.getLogger,SLF4J会查找classpath,根据classpath中引用的日志jar包决定和哪种具体的日志系统进行绑定。
package com.longji; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogTest extends BaseTestCase { @Test public void testSLF() { Logger logger = LoggerFactory.getLogger("1"); logger.error("testSLF"); } }
绑定规则参考下图
3 commons-logging(JCL)
JCL的目的和SLF4J的目标是类似的,也是为了对不同的日志系统实现进行统一抽象,让客户代码和具体的日志系统解耦。
示例:
客户调用LogFactory.getLog,JCL根据特定的查找规则拿到LogFactory实例,创建具体的logger对象。
它的查找规则是(参考http://spiritfrog.iteye.com/blog/391685)
a. 从系统属性中查找键为 org.apache.commons.logging.LogFactory 的值作为 LogFactory 的实现类;却通过 System.getProperty("org.apache.commons.logging.LogFactory") 获得
b. 使用 JDK1.3 jar 的 Service Provider Interface(SPI) 类发现机制,从配置文件 META-INF/services/org.apache.commons.logging.LogFactory 的的第一行读取 LogFactory 的实现类名。这个 META-INF/services/org.apache.commons.logging.LogFactory 文件可以是某个 Web 应用的根目录中;也可以在 classpath 下,如某个 Jar 包中,WebRoot/WEB-INF/classes 中等。这里需多加留心下 META-INF/services/org.apache.commons.logging.LogFactory 这个目录层次及文件名。
c. 在 Classpath 下的 commons-logging.properties 文件中的,找到 org.apache.commons.logging.LogFactory 属性值作为 LogFactory 实现类
d. 前面三步未找个 LogFactory 的实现类,或有任何异常的情况下,就用默认的实现类,即 LogFactory 为我们准备的 org.apache.commons.logging.impl.LogFactoryImpl
package com.longji; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogTest extends BaseTestCase { @Test public void testJCL() { Log logger = LogFactory.getLog("2"); logger.error("testJCL"); } }
4 集大成者SLF4J
JCL和SLF4J的功能类似,如果想要将JCL项目平滑迁移到SLF4J,SLF4J提供了解决方案,将org.apache.commons.logging.LogFactory.getLog()委派到SLF4J自身的factory中。
这种平滑迁移的技术是通过利用org.apache.commons.logging.LogFactory.getLog()的 Service Provider Interface(SPI) 查找规则实现的,需要在项目中引入jcl-over-slf4j.jar,jar包里的/META-INF/services/org.apache.commons.logging.LogFactory把LogFactory的具体实现指向org.apache.commons.logging.impl.SLF4JLogFactory,再由SLF4JLogFactory按照SLF4J自己的规则去绑定具体的日志系统。
(参考http://hi.baidu.com/tmser/item/15e5f0e9639ebcc3bbf37dd5,http://www.360doc.com/content/10/0908/15/1542811_52121394.shtml)
pom依赖参考
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.0.6</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.0.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.6.6</version> </dependency>