mybatis之日志框架

本篇主要来聊一下 mybatis 的日志框架,揭秘 mybtais 是如何能够集成各种不同的日志框架的。

知识点

  • 如何打印日志
  • 自定义日志实现
  • 实现原理

如何打印日志

我们平时在使用 mybatis 的时候偶尔会遇到一些问题,想要看下我们执行的sql到底是怎么样的,这时就需要将 mybtais 的执行日志打印出来了,如何打印日志呢,网上资料很多,官网也给出了说明,大概就是以下三步(以log4j2为例):

1)引入日志 jar 包

   org.apache.logging.log4j   log4j-core   2.14.1

2) 配置日志输出(如log4j2.xml)




    
        
            
        
    

    
        
        
            
        
    

Logger可以对某些项日志输出级别单独配置,防止输出太多。

3)mybatis 全局配置文件配置日志输出实现

    
        
    

通过上面几步配置就可以打印日志了。

目前 mybatis 支持的日志实现有以下几种,看名称估计大家也知道了

image.png

你没看错,mybatis 不支持 logback 实现!但是提供了 slf4j 实现,我们可以基于此使用 logback,当然你也可以通过自定义日志实现类来实现。另外可以看到,3.5.9之后版本不支持 log4j 了。各种使用方式具体可以参考官网

自定义日志实现

接着我们来看一下如何自定义一个日志实现,我们觉得 mybatis 提供的几种方式都不适合我们的业务场景,那么就需要自定义了。也只需要三步:

1)定义一个日志实现类,继承org.apache.ibatis.logging.Log接口

public class MyloggerImpl implements Log {

    public MyloggerImpl(String clazz){

    }

     /**
      * 设为true就会输出debug内容
      **/
    @Override
    public boolean isDebugEnabled() {
        return false;
    }

    /**
     * 设为true就会输出trace内容
     **/
    @Override
    public boolean isTraceEnabled() {
        return false;
    }

    @Override
    public void error(String s, Throwable throwable) {
        System.out.println("error2:" + s);
    }

    @Override
    public void error(String s) {
        System.out.println("error:" + s);
    }

    @Override
    public void debug(String s) {
        System.out.println("debug:" + s);
    }

    @Override
    public void trace(String s) {
        System.out.println("trace:" + s);
    }

    @Override
    public void warn(String s) {
        System.out.println("warn:" + s);
    }
}

2)mybatis 全局配置文件中注册这个日志实现类

    
        
    

3)mybatis 全局配置文件中将 logImpl 设置成我们上一步注册的假名

通过以上三步就完成了,我们来看下结果

image.png

我只对 isDebugEnabled()返回值返回了ture,可以看到输出了前缀带“debug:”的信息。

实现原理

日志实现

最后来看下 mybatis 日志是如何实现的。还是先看下日志实现所在包

mybatis之日志框架_第1张图片

从包名我们大致已经看到了有哪些日志实现,所有日志实现都要基于org.apache.ibatis.logging.Log接口,org.apache.ibatis.logging.LogFactory是对外提供日志对象的工厂类,这里用到了简单工厂模式,通过 getLog 方法来获取具体的日志实现对象,通过 useCustomLogging 来设置日志实现类。他有个静态代码块,用于加载默认的日志实现类,通过顺序我们也可以看出优先级。

mybatis之日志框架_第2张图片

可以看出slf4j是第一位的,也能理解,毕竟有了slf4j,基本就可以对接其他日志实现了。基于slf4j看下是怎么做的

image.png

Slf4jImpl就是LogFactory默认日志实现类对应的类型,必须要有带String参数的构造函数,因为LogFactory去获取构造函数的时候就是找的带String 参数的

mybatis之日志框架_第3张图片

Slf4jLocationAwareLoggerImplSlf4jLoggerImpl是sfl4j的两种日志实现类包装,里面还是具体用的sfl4j的Logger去做事情的,我们上面的自定义日志实现类就是这么做的。从这里可以看出来,如果我们没有配置logImpl,则默认根据顺序从你系统中找第一个有引入的日志包,最终以NoLoggingImpl兜底,不输出任何日志。

再来看下logImpl配置是如何生效的。我们知道在启动的时候mybatis会去做配置加载,最终加到的全局的 configuration 下,所以从这里我们可以找到对应的logImpl配置项加载

image.png

可以看到这里会去解析对应的实现类,并设置到LogFactory中,而对于实现类的解析,其实就是从假名列表里取的

image.png

而在org.apache.ibatis.session.Configuration#Configuration()就对日志实现类假名和对应实现类做了注册

mybatis之日志框架_第4张图片

这也是为什么我们在自定义日志实现类的时候也要注册以下的原因。

我们的sql 日志是在哪里输出的呢?每个MappedStatement都有一个statementLog,它就是通过LogFactory获取的具体实现对象,在最终做sql的时候会获取并进行打印

mybatis之日志框架_第5张图片

干净打包

我们在mybatis源码中可以看到mybatis引入了slf4j、log4j等相关依赖包,但是我们在引入mybatis的时候又没有引入这些依赖,为什么呢?

这里要说到 maven 的依赖传递相关内容,maven的依赖作用域有compile、runtime、test、provided、system、import,默认是compile,也就是会直接传递依赖,什么是传递依赖,这里就不详细介绍了,可以参考这篇文章,大概就是A依赖B,C依赖A,那么C就会把A也依赖进来,通过设置作用域,我们可以切断依赖的传递(设置为provided)。当然我们还可以通过设置optional为true来切断依赖。

设置optional和provided有什么区别呢?我认为就是场景问题,如果你认为自己的包里相关实现是必须的并且容器是会提供的,就设置provided,如果你认为某些功能不是必须的,要用容器自己去添加,则可以设置optional。来看下mybatis是怎么做的

mybatis之日志框架_第6张图片

总结

日志实现虽然比较简单,但是通过这个学习,我们了解了如何在系统中做到兼容不同日志实现,在开发工具包的时候如何做到干净打包。

参考资料

https://mybatis.org/mybatis-3...
https://blog.csdn.net/elricbo...

你可能感兴趣的:(mybatis)