JCL,全称为"Jakarta Commons Logging",也可称为"Apache Commons Logging"。

一、JCL原理

1、基本原理

JCL这个日志框架跟Log4J,Java Logging API等日志框架不同。JCL采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架,比如Log4J,Java Logging API等。

在JCL中对外有两个统一的接口,分别是Log和LogFactory。

Log的继承体系如图1:

               图1

LogFactory的继承体系如图2:

图2

Log4JLogger,Jdk14Logger等是适配类。

在Log4JLogger类中,包含有"org.apache.log4j.Logger"类,即Log4J中的Logger类,因而对Log4JLogger类中的日志操作方法的调用会被委托给"org.apache.log4j.Logger"类运行

在Jdk14Logger类中,包含有"java.util.logging.Logger"类,即Java Logging API中的Logger类,因而对Jdk14Logger类中的日志操作方法的调用会被委托给"java.util.logging.Logger"类运行

2、具体加载步骤

在执行以下Java代码语句的时候,经历了哪些步骤?


  1. Log log = LogFactory.getLog(Main.class);
  2. log.error("Hello World");

1)通过查看源代码可以发现,执行"LogFactory.getLog(Main.class)"语句的时候,最终是执行LogFactoryImp类中的discoverLogImplementation方法,在该方法中有如下代码语句:


  1. for(int i = 0; i < classesToDiscover.length && result == null; ++i)
  2. {
  3. result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
  4. }

其中classesToDiscover的值如图3所示:

图3



这个过程就是依次去判断类路径中是否存在Log4J依赖,JDK依赖等。就是经常说的JCL运行时动态查找具体日志框架的过程。

2)在1)中discoverLogImplementation方法找到具体的日志框架依赖之后,会去生成相应的适配器类实例。比如找到了Log4J日志框架依赖,那么会生成一个Log4JLogger适配器类实例(以A来表示它),并将其返回。最后该适配器类实例,被赋值给"Log log = LogFactory.getLog(Main.class)"中的log对象。

3)执行log.error("Hello World");语句,实际上是执行A中的error(Object message)方法,而该方法中会去委托"A中所包含的org.apache.log4j.Logger类实例"进行处理。

二、基本原理扩展

1、本质上说,NoOpLog和SimpleLog不是适配器类,因为它们自身实现日志操作功能,而不是委托给其他日志框架。

2、关于JCL有两个包,分别是:commons-logging:commons-logging:1.1和commons-logging:commons-logging-api:1.1

这两者的主要差别在于前者比后者拥有更多的适配器类

前者中的适配器体系见图1

后者中的适配器体系见图4

图4

3、在commons-logging:commons-logging:1.1和commons-logging:commons-logging-api:1.1的pom.xml文件中,可以发现它们有对具体日志框架的依赖,比如在commons-logging:commons-logging:1.1的pom.xml中有如下片段:


  1. <dependency>
  2. <groupId>log4j</groupId>
  3. <artifactId>log4j</artifactId>
  4. <version>1.2.12</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>avalon-framework</groupId>
  8. <artifactId>avalon-framework</artifactId>
  9. <version>4.1.3</version>
  10. </dependency>

即包含有对Log4J和avalon-framework(也是一个具体的日志框架)的依赖。其实想想也是如此,因为JCL中含有Log4JLogger,Jdk14Logger等适配器类,在这些适配器类中含有对对应的具体的日志框架的依赖,比如在Log4JLogger类中,有如下片段:


  1. package org.apache.commons.logging.impl;
  2. import java.io.Serializable;
  3. import org.apache.commons.logging.Log;
  4. import org.apache.log4j.Logger;
  5. import org.apache.log4j.Priority;
  6. public class Log4JLogger implements Log, Serializable {}

以上这点表明,在项目中,我们只要包含了对commons-logging:commons-logging:1.1或者commons-logging:commons-logging-api:1.1的依赖,就会包含所有对它们所支持的具体日志框架的依赖。因而在JCL运行时动态查找具体日志框架的过程中,能够找到所有所支持的具体日志框架,根据具体的查找算法,选定某一个返回。

但是为了更加清晰准确,我们应该还是得在项目中包含对具体日志框架的依赖比较好,比如要使用“JCL+Log4J”的组合方案,那么在项目的pom.xml中,应该包含以下片段:


  1. <dependency>
  2. <groupId>commons-logging</groupId>
  3. <artifactId>commons-logging</artifactId>
  4. <version>1.1</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>log4j</groupId>
  8. <artifactId>log4j</artifactId>
  9. <version>1.2.17</version>
  10. </dependency>

4、在JCL中一般情况下,需要有两个配置文件,一个是JCL自身的,另外一个是具体日志框架的。比如在JCL中,具体的日志框架使用Log4J,那么需要有"commons-logging.properties"和"log4j.properties"这两个文件

5、由上述第3点可以知道,最终使用的具体日志框架由查找算法决定,这降低了我们对日志框架使用的控制度。我们也可以通过JCL的配置文件,即"commons-logging.properties",来明确指定最终使用的具体日志框架,达到精准控制定义的目标。具体是配置文件中的"org.apache.commons.logging.Log"属性。

比如在"commons-logging.properties"文件中,配置

org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger

那么显式指定使用Log4J这个具体日志框架,然后也生成"org.apache.commons.logging.impl.Log4JLogger"的一个实例

三、JCL如何使用的具体例子

1、JCL+Log4J

1.1、项目中的pom.xml配置


  1. <dependencies>
  2. <dependency>
  3. <groupId>commons-logging</groupId>
  4. <artifactId>commons-logging</artifactId>
  5. <version>1.1</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>log4j</groupId>
  9. <artifactId>log4j</artifactId>
  10. <version>1.2.17</version>
  11. </dependency>
  12. </dependencies>

1.2、commons-logging.properties和log4j.properties两个文件的内容

"commons-logging.properties"文件内容如下:

org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger

"log4j.properties"文件内容如下:

# Root logger option
log4j.rootLogger=INFO, stdout # Direct log messages to stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.out

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

1.3、Java代码


  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Log log = LogFactory.getLog(Main.class);
  6. log.error("Hello World");
  7. System.out.println(log.getClass());
  8. }
  9. }

1.4、输出结果

如图5

图5

2、JCL+Log4J

2.1、项目中的pom.xml配置


  1. <dependencies>
  2. <dependency>
  3. <groupId>commons-logging</groupId>
  4. <artifactId>commons-logging</artifactId>
  5. <version>1.1</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>log4j</groupId>
  9. <artifactId>log4j</artifactId>
  10. <version>1.2.17</version>
  11. </dependency>
  12. </dependencies>

2.2、commons-logging.properties和log4j.properties两个文件的内容

"commons-logging.properties"文件内容如下:

org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger

"log4j.properties"文件不存在

2.3、Java代码


  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Log log = LogFactory.getLog(Main.class);
  6. log.error("Hello World");
  7. System.out.println(log.getClass());
  8. }
  9. }

2.4、输出结果

如图6

图6

3、JCL+Java Logging API

3.1、项目中的pom.xml配置


  1. <dependency>
  2. <groupId>commons-logging</groupId>
  3. <artifactId>commons-logging</artifactId>
  4. <version>1.1</version>
  5. </dependency>
  6. <!--对JDK的依赖无需在pom.xml中配置-->

3.2、commons-logging.propertie和logging.properties两个文件的内容

"commons-logging.properties"文件内容如下:

org.apache.commons.logging.Log = org.apache.commons.logging.impl.Jdk14Logger

"logging.properties"文件是Java Logging API默认的配置文件名称,默认路径是JDK_HOME/jre/lib/logging.properties

3.3、Java代码


  1. import org.apache.commons.logging.Log;
  2. import org.apache.commons.logging.LogFactory;
  3. public class Main {
  4. public static void main(String[] args) {
  5. Log log = LogFactory.getLog(Main.class);
  6. log.error("Hello World");
  7. System.out.println(log.getClass());
  8. }
  9. }

3.4、输出结果

如图7

图7



四、其他

1、在项目中使用JCL的好处是降低与具体日志框架的耦合,可以灵活改变使用的具体日志框架

2、经典的日志框架组合为:JCL+Log4J

3、Spring项目中就选用了JCL框架

参考文献:

[1]http://commons.apache.org/proper/commons-logging/guide.html

[2]http://www.javapractices.com/topic/TopicAction.do?Id=143

原文地址:https://blog.csdn.net/DSLZTX/article/details/47132329

Java日志框架——JCL的更多相关文章

  1. java日志框架与日志系统

    日志框架:提供日志调用的接口,实际的日志输出委托给日志系统实现. JCL(Jakarta Commons Logging):比较流行的日志框架,很多框架都依赖JCL,例如Spring等. SLF4j: ...

  2. Java日志框架那些事儿

    文章首发于[博客园-陈树义],点击跳转到原文Java日志框架那些事儿. 在项目开发过程中,我们可以通过 debug 查找问题.而在线上环境我们查找问题只能通过打印日志的方式查找问题.因此对于一个项目而 ...

  3. Java程序员最常用的8个Java日志框架

    转自:http://www.codeceo.com/article/8-java-log-framework.html 作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用 ...

  4. 转:Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  5. Java 日志框架终极教程

    概述 对于现代的 Java 应用程序来说,只要被部署到真实的生产环境,其日志的重要性就是不言而喻的,很难想象没有任何日志记录功能的应用程序被运行于生产环境中.日志 API 所能提供的功能是多种多样的, ...

  6. Java基础学习总结(40)——Java程序员最常用的8个Java日志框架

    作为一名Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日志可以帮助我们更好更快地定位bug:在 ...

  7. Java日志框架总结

    1. 前言 从写代码开始,就陆陆续续接触到了许多日志框架,较常用的属于LOG4J,LogBack等.每次自己写项目时,就copy前人的代码或网上的demo.配置log4j.properties或者lo ...

  8. Java-最常用的Java日志框架整理

    Java-最常用的Java日志框架整理 前言 Java程序员,我们开发了很多Java应用程序,包括桌面应用.WEB应用以及移动应用.然而日志系统是一个成熟Java应用所必不可少的,在开发和调试阶段,日 ...

  9. java日志框架系列(4):logback框架xml配置文件语法

    1.xml配置文件语法 由于logback配置文件语法特别灵活,因此无法用DTD或schema进行定义. 1.配置文件基本结构 配置文件基本结构:以<configuration>标签开头, ...

随机推荐

  1. 【指南】本地如何搭建IPv6环境测试你的APP

    由于苹果最近更新IOS10之后他们的工作环境升级了,统一用IPV6网络,所以我们发出去的申请的APP不兼容IPV6的话,会通过不了审核! 所幸的是苹果会自动把你服务器要接的协议自动把iPV6转成IPV ...

  2. python csv文件打开错误:_csv.Error: line contains NULL byte

    当python读取文件出现_csv.Error: line contains NULL byte时, # -*- coding:utf-8 -*- import csv with open(r'E:\ ...

  3. oracle 处理表的一列

    ---删除一列和数据一起删除了. ALTER TABLE 表名 DROP COLUMN 列名; ---添加一列 alert table 表名 add column 列名; ---只删除一列的数据 没有 ...

  4. Leetcode762.Prime Number of Set Bits in Binary Representation二进制表示中质数个计算置位

    给定两个整数 L 和 R ,找到闭区间 [L, R] 范围内,计算置位位数为质数的整数个数. (注意,计算置位代表二进制表示中1的个数.例如 21 的二进制表示 10101 有 3 个计算置位.还有, ...

  5. Webpack ERROR in Path must be a string. Received undefined

    在学习webpack过程中,我遇到的下面这个问题及解决方法. 问题如下: node版本如下截图: package.json文件截图: webpack.config.js文件截图: 然后,我运行项目,报 ...

  6. 国内首个全域边缘节点服务发布,阿里云助力企业把握5G机遇

    7月24日,阿里云峰会开发者大会在上海世博中心举办.作为2019年首场最受瞩目的云计算开发者大会,阿里云携一众云计算技术大牛与开发者面对面,探讨各自领域的技术干货与前沿趋势.同时,也发布了多项重大重磅 ...

  7. LDAP Authentication Handler

    Including the Handler In the pom.xml file for your CAS Maven2 WAR Overlay, add the following depende ...

  8. 【JZOJ4964】【GDKOI2017模拟1.21】Rhyme

    hafy 由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部.无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子.为了让自己的曲子更好听,小Z找到了一些好听曲子作为 ...

  9. 【JZOJ4788】【NOIP2016提高A组模拟9.17】序列

    题目描述 输入 输出 样例输入 1 5 2 1 3 0 3 2 2 0 1 0 样例输出 1 数据范围 解法 考虑没有模的情况,问题就仅仅只是简单的差分问题(广告铺设): 设r[i]是第i位需要加的次 ...

  10. nodeJs学习-09 模板引擎 jade、ejs

    模板引擎: jade -破坏式.侵入式,强依赖:用了之后不能随便用别的引擎 ejs - 温和.非侵入时.弱依赖 jade使用 const jade = require('jade'); var str ...