java日志组件的关系 slf4j logback log4j

 

 

 

 

 

转自:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412364.htmlhtml

common-logging是apache提供的一个通用的日志接口。用户能够自由选择第三方的日志组件做为具体实现,像log4j,或者jdk自带的logging, common-logging会经过动态查找的机制,在程序运行时自动找出真正使用的日志库。固然,common-logging内部有一个Simple logger的简单实现,可是功能很弱。因此使用common-logging,一般都是配合着log4j来使用。使用它的好处就是,代码依赖是 common-logging而非log4j, 避免了和具体的日志方案直接耦合,在有必要时,能够更改日志实现的第三方库。java

使用common-logging的常见代码:
[java]  view plain copy
  1. import org.apache.commons.logging.Log;  
  2. import org.apache.commons.logging.LogFactory;  
  3.   
  4. public class A {  
  5.     private static Log logger = LogFactory.getLog(this.getClass());  
  6. }  
动态查找原理:Log 是一个接口声明。LogFactory 的内部会去装载具体的日志系统,并得到实现该Log 接口的实现类。LogFactory 内部装载日志系统的流程以下:
  1. 首先,寻找org.apache.commons.logging.LogFactory 属性配置。
  2. 不然,利用JDK1.3 开始提供的service 发现机制,会扫描classpah 下的META-INF/services/org.apache.commons.logging.LogFactory文件,若找到则装载里面的配置,使用里面的配置。
  3. 不然,从Classpath 里寻找commons-logging.properties ,找到则根据里面的配置加载。
  4. 不然,使用默认的配置:若是能找到Log4j 则默认使用log4j 实现,若是没有则使用JDK14Logger 实现,再没有则使用commons-logging 内部提供的SimpleLog 实现。
从上述加载流程来看,只要引入了log4j.jar 并在classpath 配置了log4j.xml ,则commons-logging 就会使log4j 使用正常,而代码里不须要依赖任何log4j 的代码。

slf4j

slf4j全 称为Simple Logging Facade for JAVA,java简单日志门面。相似于Apache Common-Logging,是对不一样日志框架提供的一个门面封装(是接口而非实现),能够在部署的时候不修改任何配置便可接入一种日志实现方案。可是,他在编译时静态绑定真正的Log库。使用SLF4J时,若是你须要使用某一种日志实现,那么你必须选择正确的SLF4J的jar包的集合(各类桥接包)。apache

使用slf4j的常见代码:
编程

[java]  view plain copy
  1. import org.slf4j.Logger;  
  2. import org.slf4j.LoggerFactory;  
  3.   
  4. public class A {  
  5.     private static Logger logger = LoggerFactory.getLogger(RdpMonitorService.class); 
  6. }  


slf4j静态绑定原理SLF4J 会在编译时会绑定import org.slf4j.impl.StaticLoggerBinder; 该类里面实现对具体日志方案的绑定接入。任何一种基于slf4j 的实现都要有一个这个类。如:org.slf4j.slf4j-log4j12-1.5.6: 提供对 log4j 的一种适配实现。
api

注意:若是有任意两个实现slf4j 的包同时出现,那么就可能出现问题。
框架

slf4j 与 common-logging 比较(都是日志接口而非实现)

common-logging经过动态查找的机制, 在程序运行时自动找出真正使用的日志库。因为它使用了ClassLoader寻找和载入底层的日志库, 致使了象OSGI这样的框架没法正常工做,由于OSGI的不一样的插件使用本身的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging没法工做。

slf4j编译时静态绑定真正的Log库,所以能够再OSGI中使用。另外,SLF4J 支持参数化的log字符串,避免了以前为了减小字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),如今你能够直接写:logger.debug(“current user is: {}”, user)。拼装消息被推迟到了它可以肯定是否是要显示这条消息的时候,可是获取参数的代价并无幸免。

Log4j

Apache 的一个开放源代码项目,经过使用Log4j,咱们能够控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;用户也能够控制每一条日志的输出格式;经过定义每一条日志信息的级别,用户可以更加细致地控制日志的生成过程。这些能够经过一个 配置文件来灵活地进行配置,而不须要修改程序代码。

LogBack

Logback 是由log4j创始人设计的又一个开源日记组件。logback当前分红三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个改良版本。此外logback-classic完整实现SLF4J API使你能够很方便地更换成其它日记系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供经过Http来访问日记的功能。 

Log4j 与 LogBack 比较(都是日志记录器的实现)

LogBack 做为一个通用可靠、快速灵活的日志框架,将做为Log4j的替代和SLF4J组成新的日志系统的完整实现。LogBack声称具备极佳的性能,“ 某些关键操做,好比断定是否记录一条日志语句的操做,其性能获得了显著的提升。这个操做在LogBack中须要3纳秒,而在Log4J中则须要30纳秒。 LogBack建立记录器(logger)的速度也更快:13微秒,而在Log4J中须要23微秒。更重要的是,它获取已存在的记录器只需94纳秒,而 Log4J须要2234纳秒,时间减小到了1/23。跟JUL相比的性能提升也是显著的”。 另外,LOGBack的全部文档是全面免费提供的,不象Log4J那样只提供部分免费文档而须要用户去购买付费文档。 
 

slf4j与其余各类日志组件的桥接

应用代码中使用slf4j接口,接入具体实现的方法

应用代码中使用别的日志接口,转成slf4j的方法


日志组件相关历史

Java 界里有许多实现日志功能的工具,最先获得普遍使用的是 log4j,许多应用程序的日志部分都交给了 log4j,不过做为组件开发者,他们但愿本身的组件没关系紧依赖某一个工具,毕竟在同一个时候还有不少其余不少日志工具,假如一个应用程序用到了两个组件,刚好两个组件使用不一样的日志工具,那么应用程序就会有两份日志输出了。

为了解决这个问题,Apache Commons Logging (以前叫 Jakarta Commons Logging,JCL)粉墨登场,JCL 只提供 log 接口,具体的实现则在运行时动态寻找。这样一来组件开发者只须要针对 JCL 接口开发,而调用组件的应用程序则能够在运行时搭配本身喜爱的日志实践工具。

因此即便到如今你仍会看到不少程序应用 JCL + log4j 这种搭配,不过当程序规模愈来愈庞大时,JCL的动态绑定并非总能成功,具体缘由你们能够 Google 一下,这里就再也不赘述了。解决方法之一就是在程序部署时静态绑定指定的日志工具,这就是 SLF4J 产生的缘由。

跟 JCL 同样,SLF4J 也是只提供 log 接口,具体的实现是在打包应用程序时所放入的绑定器(名字为 slf4j-XXX-version.jar)来决定,XXX 能够是 log4j12, jdk14, jcl, nop 等,他们实现了跟具体日志工具(好比 log4j)的绑定及代理工做。举个例子:若是一个程序但愿用 log4j 日志工具,那么程序只需针对 slf4j-api 接口编程,而后在打包时再放入 slf4j-log4j12-version.jar(绑定器) 和 log4j.jar(具体实现) 就能够了。

如今还有一个问题,假如你正在开发应用程序所调用的组件当中已经使用了 JCL 的,还有一些组建可能直接调用了 java.util.logging,这时你须要一个桥接器(名字为 XXX-over-slf4j.jar)把他们的日志输出重定向到 SLF4J,所谓的桥接器就是一个假的日志实现工具,好比当你把 jcl-over-slf4j.jar 放到 CLASS_PATH 时,即便某个组件本来是经过 JCL 输出日志的,如今却会被 jcl-over-slf4j “骗到”SLF4J 里,而后 SLF4J 又会根据绑定器把日志交给具体的日志实现工具。过程以下

Component
|
| log to Apache Commons Logging
V
jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> 输出日志

看到上面的流程图可能会发现一个有趣的问题,假如在 CLASS_PATH 里同时放置 log4j-over-slf4j.jar 和 slf4j-log4j12-version.jar 会发生什么状况呢?没错,日志会被踢来踢去,最终进入死循环。

因此使用 SLF4J 的比较典型搭配就是把 slf4j-api、JCL 桥接器、java.util.logging(JUL)桥接器、log4j 绑定器、log4j 这5个 jar 放置在 CLASS_PATH 里。

不过并非全部APP容器都是使用 log4j 的,好比 Google AppEngine 它使用的是 java.util.logging(JUL),这时应用 SLF4J 的搭配就变成 slf4j-api、JCL桥接器、logj4桥接器、JUL绑定器这4个 jar 放置在 WEB-INF/lib 里。
转自:http://www.blogjava.net/daiyongzhi/archive/2014/04/13/412363.html

几乎在每一个jar包里均可以看到log4j的身影,在多个子工程构成项目中,slf4j相关的冲突时不时就跳出来让你不爽,那么slf4j-api、slf4j-log4j12还有log4j他们是什么关系?我把本身了解的和你们简单分享一下:工具

    slf4j:Simple Logging Facade for Java,为java提供的简单日志Facade。Facade:门面,更底层一点说就是接口。他容许用户以本身的喜爱,在工程中经过slf4j接入不一样 的日志系统。更直观一点,slf4j是个数据线,一端嵌入程序,另外一端连接日志系统,从而实现将程序中的信息导入到日志系统并记录。 性能

   所以,slf4j入口就是众多接口的集合,他不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。具体有哪些接口,所有都定义在slf4j-api中。查看slf4j-api源码就能够发现,里面除了public final class LoggerFactory类以外,都是接口定义。所以,slf4j-api本质就是一个接口定义。this

      

下图比较清晰的描述了他们之间的关系:url


   

     

 

  当系统采用log4j做为日志框架实现的调用关系:

    

    首先系统包含slf4j-api做为日志接入的接口;

    

    at compile时slf4j-api中public final class LoggerFactor类中

    private final static void bind() 方法会寻找具体的日志实现类绑定,主要经过
    StaticLoggerBinder.getSingleton();语句调用

    

  

   slf4j-log4j12:连接slf4j-api和log4j中间的适配器。它实现了slf4j-apiz中StaticLoggerBinder接口,从而使得在编译时绑定的是slf4j-log4j12的getSingleton()方法

log4j:这个是具体的日志系统。经过slf4j-log4j12初始化Log4j,达到最终日志的输出。

 

 

 

 

============================================================================

本身的理解

1)apache common-logging 和 slf4j 都是日志接口,而非实现,虽然他们可能自带有一个极简的实现;

2)log4j、logback、还有 log4j2 等都是日志记录器的实现;

3)日志接口如何查找日志实现类库: common-logging 经过动态绑定,到classpath去寻找;

     slf4j 编译时会静态绑org.slf4j.impl.StaticLoggerBinder这个类,而其余的日志实现 log4j、logback 的实现中包括该类的实现,具体实现代码就是绑定  本身的实现到 slf4j .

4)采用 slf4j 接口时,会涉及到 绑定器 和 桥接器 。slf4j-log4j12-version.jar 绑定 slf4j到log4j,jcl-over-slf4j 将采用jcl接口的日志都桥接到slf4j接口,而后会采用slf4j的绑定器中绑定的日志实现来记录日志。

5)使用 SLF4J 的比较典型搭配就是把 slf4j-api、JCL 桥接器、java.util.logging(JUL)桥接器、log4j 绑定器、log4j 这5个 jar 放置在 CLASS_PATH 里。原理就是使用 slf4j 的各类桥接器,将全部日志接口都桥接到 slf4j 这个接口,而后选择一个具体的 slf4j 绑定器 和 日志实现器,达到将全部日志统一使用一个日志实现器进行统一输出的目的。

6)slf4j-api.jar 是slf4j自身的接口,common-logging.jar是接口,log4j.jar, logback.jar,log4j2.jar是实现;jcl-over-slf4j是jcl桥接到slf4j的jar包;slf4j-log4j.jar是slf4j绑定到log4j的jar包。

因此分为:接口jar包、实现jar包、桥接到slf4j的jar包、slf4j绑定到实现的jar包接口到接口是经过桥接包,接口到实现是经过绑定包

7)最后给出两个实例:

1> slf4j + log4j:

复制代码
        <!-- slf4j interface--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> </dependency> <!-- jcl bridge to slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.6.1</version> </dependency> <!-- slf4j binding to log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency> <!-- log4j recorder --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
复制代码

2> slf4j + logback 最简形式:

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.3</version> </dependency> 

logback会自动引入 logback-core 和 slf4j:

3> slf4j + logback + jcl桥接:

复制代码
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.6.1</version> </dependency>
复制代码

看起来 logback 配置确实比log4j要简单得多。

相关文章
相关标签/搜索