# JCL

# JCL简介

全称为Jakarta Commons Logging,是Apache提供的一个通用日志API

用户可以自由选择第三方的日志组件作为具体实现,像 log4j,或者 jdk 自带的 jul,common-logging 会通过动态查找的机制,在程序运行时自动找出真正使用的日志库。

当然,common-logging 内部有一个Simple logger 的简单实现,但是功能很弱。所以使用common-logging,通常都是配合着log4j以及其他日志框架来使用。

使用它的好处就是,代码依赖是 common-logging而非log4j的API, 避免了和具体的日志API直接耦合,在有必要时,可以更改日志实现的第三方库。

JCL 有两个基本的抽象类:

Log:日志记录器。

LogFactory:日志工厂(负责创建 Log 实例)

img

# 案例

# 引入依赖

  			<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
1
2
3
4
5
6
7
8
9
10
11
12

# 入门案例

在没有导入第三方的日志框架情况下,例如log4j,会使用JUL日志框架做日志的记录操作

*JCL使用的原则: **如果有log4j,优先使用log4j *如果项目中没有任何第三方日志框架,使用的就是JUL

 		@Test
    public void testJCL(){

        Log log = LogFactory.getLog(JCLTest.class);
        log.fatal("========= FATAL信息 test jcl =========");
        log.error("========= ERROR信息 test jcl =========");
        log.warn("========= WARN信息 test jcl =========");
        log.info("========= INFO信息 test jcl =========");
        log.debug("========= DEBUG信息 test jcl =========");
        log.trace("========= TRACE信息 test jcl =========");


        /**
         * 输出结果:(JUL日志格式默认风格)
         * 一月 22, 2022 3:35:26 下午 cn.giteasy.jcl.test.JCLTest testJCL
         * 严重: ========= FATAL信息 test jcl =========
         * 一月 22, 2022 3:35:26 下午 cn.giteasy.jcl.test.JCLTest testJCL
         * 严重: ========= ERROR信息 test jcl =========
         * 一月 22, 2022 3:35:26 下午 cn.giteasy.jcl.test.JCLTest testJCL
         * 警告: ========= WARN信息 test jcl =========
         * 一月 22, 2022 3:35:26 下午 cn.giteasy.jcl.test.JCLTest testJCL
         * 信息: ========= INFO信息 test jcl =========
         */
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# JCL引入log4j依赖

添加依赖

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
1
2
3
4
5

添加配置文件log4j.properties

log4j.rootLogger = trace,consoleAppender,fileAppender


#*********************************************************************************************
#配置appender输出方式为控制台输出

log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %l %m%n

#*********************************************************************************************
#配置appender输出到文件中
log4j.appender.fileAppender = org.apache.log4j.FileAppender
log4j.appender.fileAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.conversionPattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %l %m%n
log4j.appender.fileAppender.file = D:\\log4j_test.log
log4j.appender.fileAppender.encoding = UTF-8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

测试类

		@Test
    public void testUCL_Log4j(){
        Log log = LogFactory.getLog(JCLTest.class);
        log.fatal("========= FATAL信息 test jcl =========");
        log.error("========= ERROR信息 test jcl =========");
        log.warn("========= WARN信息 test jcl =========");
        log.info("========= INFO信息 test jcl =========");
        log.debug("========= DEBUG信息 test jcl =========");
        log.trace("========= TRACE信息 test jcl =========");

        /**
         * 输出信息:
         *
         * log4j:WARN No appenders could be found for logger (cn.giteasy.jcl.test.JCLTest).
         * log4j:WARN Please initialize the log4j system properly.
         * log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
         *
         *
         * 我们观察控制台打印日志,可以发现已经使用了log4j作为日志输出,
         * 警告信息为没有发现Appender,是因为没有进行log4j的相关配置,需要log4j.properties配置文件进行配置,
         *
         * 进行配置后输出信息:
         * 2022-01-22 15:42:16.053 [main] FATAL cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:54) ========= FATAL信息 test jcl =========
         * 2022-01-22 15:42:16.056 [main] ERROR cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:55) ========= ERROR信息 test jcl =========
         * 2022-01-22 15:42:16.056 [main] WARN  cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:56) ========= WARN信息 test jcl =========
         * 2022-01-22 15:42:16.057 [main] INFO  cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:57) ========= INFO信息 test jcl =========
         * 2022-01-22 15:42:16.057 [main] DEBUG cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:58) ========= DEBUG信息 test jcl =========
         * 2022-01-22 15:42:16.057 [main] TRACE cn.giteasy.jcl.test.JCLTest.testUCL_Log4j(JCLTest.java:59) ========= TRACE信息 test jcl =========
         *
         *
         *
         *
         */
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 总结:

虽然日志框架进行了改变,但是代码完全没有改变。

日志门面的好处:

门面技术是面向接口的开发,不再依赖具体的实现类,减少代码的耦合性。

可以根据实际需求,灵活的切换日志框架。

统一的API,方便开发者学习和使用,统一的配置管理便于项目日志的维护

# 源码分析

Log接口的4个实现类

  • JDk13
  • JDK14 正常java.util.logging
  • Log4j 我们集成的log4j
  • Simple JCL自带实现类

img

(1)查看Jdk14Logger证明里面使用的是JUL日志框架

img (2)查看Log4JLogger证明里面使用的是Log4j日志框架

img (3)观察LogFactory,查看如何加载的Logger对象

imgimg 这是一个抽象类,无法实例化,需要观察其实现类LogFactoryImpl (4)观察LogFactoryImpl,真正加载日志实现使用的就是这个实现类LogFactoryImpl (5)进入getLog方法 进入getInstance方法 找到instance = this.newInstance(name);//继续进入

img 找到instance = this.discovertogImplementation(name);// 表示发现一个日志的实现

img

img 遍历我们拥有的日志实现框架,遍历的是一个数组,这个数组是按照 log4j、 jdk14、jdk13、SimpleLogger的顺序依次遍历 表示的是,第一个要遍历的就是log4j,如果有log4j则执行该日志框架,如果没有,则遍历出来第二个,使用jdk14的JUL日志框架,以此类推.

result = this createLogFromclass(classesToDiscover[i], logCategory, true);
1

表示帮我们创建Logger对象在这个方法中,我们看到了

c = class.forName(logAdapterclassName, true, currentCL);
1
是取得该类型的反射类型对象,使用反射的形式帮我们创建logger对象
constructor = c.getconstructor(this.logConstructorsignature);
1
上次更新: 2024/7/11