MyBatis 源码学习9——MyBatis日志

一、Java日志体系

目前比较常用的日志框架:

Log4j:一个基于Java的日志记录工具,现在则是Apache软件基金会的一个项目。
Log4j 2:Apache Log4j 2是Apache开发的一款Log4j的升级产品。
Commons Logging:Apache基金会所属的项目,是一套Java日志接口。
SLF4J:类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。
Logback:一套日志组件的实现,属于SLF4J阵营。
JUL:全称是Java Util Logging,是JDK1.4以后提供的日志实现。

现在系统常用的:Slf4J +log4j2(两者关联需要使用log4j-slf4j-impl桥接包)

SLF4J (Simple Logging Facade for Java):
简单日志门面,本身不替供日志具体实现,只通过Facade Pattern门面模式对外提供一些Java Logging API,其对外提供的核心API是一些接口以及一个LoggerFactory的工厂类。

其中,SLF4J-api中定义了日志接口。开发者需要关心的就是这个接口,无须关心下层如何实现,同时各个SLF4J接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容。

log4j:
一个用Java编写的可靠,快速和灵活的日志框架(API),主要有三个主要组成部分:
loggers: 负责捕获记录信息。
appenders : 负责发布日志信息,以不同的首选目的地。
layouts: 负责格式化不同风格的日志信息。

log4j-slf4j-impl桥接包
可以理解为对Log4j的适配器,都实现了SLF4J-api中定义的日志操作规范,把对log4j的调用转接到SLF4J-api

JAVA日志体系:
log4j2配置文件log4j2.xml详解(转载)
想要更新详细的配置文件

日志接口需要与具体的日志框架进行绑定,如果项目中使用JCL作为日志接口,则需要在Classpath下新增一个commons-logging.properties文件,通过该文件指定日志工厂的具体实现,例如:
如果需要修改具体的日志实现,则只需要修改org.apache.commons.logging.Log属性值,应用代码无须做任何调整。
MyBatis 源码学习9——MyBatis日志_第1张图片
JAVA日志框架之间的关系

二、MyBatis日志实现

主要用到的类或接囗
org.apache.ibatis.logging.Log
org.apache.ibatis.logging.Log的七个实现类,对映七种日志实现
org.apache.ibatis.logging.LogFactory
org.apache.ibatis.session.Configuration

Log接口:定义日志操作规范

Log实现类:调用对应日志框架相关的API打印日志,共七种,说明MyBatis共支持7种不同的日志实现。
MyBatis 源码学习9——MyBatis日志_第2张图片

Apache Commons Logging:使用JCL输出日志。
Log4j 2:使用Log4j 2框架输入日志。
Java Util Logging:使用JDK内置的日志模块输出日志。
Log4j:使用Log4j框架输出日志。
No Logging:不输出任何日志。
SLF4J:使用SLF4J日志门面输出日志。
Stdout:将日志输出到标准输出设备(例如控制台)。

以Log4jImpl为例介绍Log实现类

Log4jImpl构造方法:获取Log4j框架中的Logger对象,然后将日志输出操作委托给Logger对象来完成。

MyBatis 源码学习9——MyBatis日志_第3张图片

MyBatis的Log实例采用工厂模式创建,即通过LogFactory获取Log实例:
MyBatis 源码学习9——MyBatis日志_第4张图片

MyBatis两种指定日志框架的方式

**第一种:**MyBatis框架在未指定日志实现的情况下能够自动从Classpath中发现日志框架,查找日志框架的顺序为SLF4J→JCL→Log4j 2→Log4j→JUL→No Logging,如果Classpath下有对应的日志包,则使用该日志框架打印日志。

LogFactory初始化代码块
MyBatis 源码学习9——MyBatis日志_第5张图片
1.尝试调用useSLF4JLogging()方法使用SLF4J日志框架,方法内部调用setImplementation()方法。

2.setImplementation()方法中,如果Classpath中不存在SLF4J日志框架相关JAR包,方法会抛出ClassNotFoundException异常或NoClassDefFoundError错误,但是方法对报错进行了捕获,只是不做任何处理,若Classpath中存在SLF4J框架相关JAR包,则使用SLF4JImpl日志实现类输出日志,并将LogFacotry的logConstructor属性指定为SLF4JImpl类对应的Constructor对象。

3.调用LogFactory类的tryImplementation()方法,方法的参数是一个Runnable的匿名对象,方法中会判断logConstructor是否为空,如果不为空,在run()方法中调用useSLF4JLogging()等方法指定日志实现类,如果为空,后续设置日志实现类的逻辑都不会执行。
MyBatis 源码学习9——MyBatis日志_第6张图片

4.如果Classpath下不存在任何日志框架,则使用NoLoggingImpl日志实现类,即不输出任何日志。

LogFactory类setImplementation()方法的实现:
MyBatis 源码学习9——MyBatis日志_第7张图片

1.获取MyBatis日志实现类对应的Constructor对象,

2.通过LogFactory类的logConstructor属性记录当前日志实现类的Constructor对象。

当我们调用LogFactory类的useLog4JLogging()方法时,就确定了使用org.apache.ibatis.logging.log4j.Log4jImpl实现类输出日志,而Log4jImpl实现类又将日志输出操作委托给Log4j框架,这样就确定了使用Log4j框架输出日志。

第二种:通过配置文件指定日志实现,参数为logImpl,其值可以是日志实现类的完全限定名或SLF4J、LOG4J、LOG4J2等别名,别名存放在Configuration类的构造方法中。

在这里插入图片描述
Configuration类的setLogImpl()方法设置日志实现类:
MyBatis 源码学习9——MyBatis日志_第8张图片

1.将logImpl值赋值给Configuration对象的属性logImpl,logImpl属性值有SLF4J,LOG4J2,或者日志实现类的完全限定名,能使用别名是因为Configuration类的构造方法中,为这些日志实现类注册了别名:
MyBatis 源码学习9——MyBatis日志_第9张图片

2.调用LogFactory类的useCustomLogging()方法指定日志实现类。
MyBatis 源码学习9——MyBatis日志_第10张图片

你可能感兴趣的:(mybatis)