java日志:三、JCL使用
1 介绍
全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。它是为"所有的Java日志实现",提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常弱(SimpleLog),故而一般不单独使用它(作为统一接口调用,换日志框架,比如换成log4j,切换依赖即可)。它允许开发人员使用不同的具体日志实现工具;Log4j,JDK自带的日志(JUL)。
JCL有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。
APP(Java应用)->JCL->log4j;jdk14(也就是JUL);simpleLog
2 依赖配置
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
3 JCL初识
JCL:如果使用的时候,没有安装log4j的依赖,那么默认使用jdk14自带的JUL日志框架,如果log4j依赖配置了,那么就会使用log4j,效果如下(此时配置了log4j的依赖及其相关的log4j.properties):
log4j.properties:
#指定RootLogger 顶级父元素默认配置信息
#指定日志的级别是WARN,使用的appender是conso
log4j.rootLogger=WARN,conso
#指定控制台日志输出的appender
log4j.appender.conso=org.apache.log4j.ConsoleAppender
#指定消息格式 layout
log4j.appender.conso.layout=org.apache.log4j.PatternLayout
#指定消息格式的内容
log4j.appender.conso.layout.conversionPattern=[%-10p]%r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
#%m 输出代码中指定的日志信息
#%p 输出优先级,DEBUG、INFO等
#%n 换行符(Windows平台的换行符为"\r\n",Unix平台是"\n")
#%r 输出自应用启动到输出该log信息耗费的毫秒数
#%c 输出打印语句所属的类的全名
#%t 输出产生该日志的线程全名
#%d 输出服务器当前时间,默认为ISO8601,也可指定格式,如:%d{yyyy年MM月dd日 HH:mm:ss.SSS}
#%l 输出日志时间发生的位置,包括类名、线程、及在代码中的行数。如:Test.main(Test.java:12)
#%F 输出日志消息产生时所在的文件名称
#%L 输出代码中的行号
#%% 输出"%"字符
package com.base7;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.Test;
public class JCLTest {
@Test
public void test01(){
//获取log日志记录器对象
Log log= LogFactory.getLog(JCLTest.class);
//日志记录输出
log.fatal("hello fatal jcl");
log.error("hello error jcl");
log.warn("hello warn jcl");
log.info("hello info jcl");
}
}
[FATAL ]0 com.base7.JCLTest.test01(JCLTest.java:13) 2021-11-05 10:32:16.260 hello fatal jcl
[ERROR ]0 com.base7.JCLTest.test01(JCLTest.java:14) 2021-11-05 10:32:16.260 hello error jcl
[WARN ]0 com.base7.JCLTest.test01(JCLTest.java:15) 2021-11-05 10:32:16.260 hello warn jcl
3.1 为何使用日志门面
1 面向接口开发,不再依赖具体的实现类。减少代码的耦合
2 项目通过导入不同的日志实现类,可以灵活的切换日志框架
3 统一API,方便开发者学习和使用
4 统一配置便于项目日志的管理
4 JCL原理
1 通过LogFactory动态加载Log实现类
JDK14Logger;Log4JLogger;SimpleLog;Jdk13LumberjackLogger ->Log
2 日志门面支持的日志实现数组
private static final String[] classesToDiscover = new String[]{"org.apache.commons.logging.impl.Log4JLogger", "org.apache.commons.logging.impl.Jdk14Logger", "org.apache.commons.logging.impl.Jdk13LumberjackLogger", "org.apache.commons.logging.impl.SimpleLog"};
3 获取具体的日志实现
for(int i = 0; i < classesToDiscover.length && result == null; ++i) {
result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
}
查看Log接口的接口实现类(idea快捷键:ctrl+alt+鼠标左键)
查看LogFactory类(抽象类):
抽象类不能创建实例,继续看代码的实现(ctrl+alt+鼠标左键):
打上断点调试源码运行情况:
跳出再进入:
跳转到断点后,点击进入:
点击两下step over,进入else:
返回的result是日志的实现,因为后面没有处理了:
源码可知,读取到一个日志的结果,result不为空,就会跳出for循环,直接返回
private static final String[] classesToDiscover = new String[]{
"org.apache.commons.logging.impl.Log4JLogger",
"org.apache.commons.logging.impl.Jdk14Logger",
"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
"org.apache.commons.logging.impl.SimpleLog"};
所以上述可知,没有安装Log4j时候,第一次循环拿不到结果,第二次使用JDK14自带的logger返回结果;如果存在了Log4j,那么第一次就会返回,也就是有Log4j就用Log4j,所以以上变量的定义顺序很重要。