乐趣区

关于mybatis:mybatis之日志框架

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

知识点

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

如何打印日志

咱们平时在应用 mybatis 的时候偶然会遇到一些问题,想要看下咱们执行的 sql 到底是怎么样的,这时就须要将 mybtais 的执行日志打印进去了,如何打印日志呢,网上材料很多,官网也给出了阐明,大略就是以下三步(以 log4j2 为例):

1)引入日志 jar 包

<dependency>   <groupId>org.apache.logging.log4j</groupId>   <artifactId>log4j-core</artifactId>   <version>2.14.1</version></dependency>

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

<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">

    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="%5level [%t] - %msg%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Logger name="com.example.mybatisanalyze.mapper" level="debug"/>
        <Root level="info" >
            <AppenderRef ref="stdout"/>
        </Root>
    </Loggers>

</Configuration>

Logger 能够对某些项日志输入级别独自配置,避免输入太多。

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

    <settings>
        <setting name="logImpl" value="LOG4J2"/>
    </settings>

通过下面几步配置就能够打印日志了。

目前 mybatis 反对的日志实现有以下几种,看名称预计大家也晓得了

你没看错,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 全局配置文件中注册这个日志实现类

    <typeAliases>
        <typeAlias alias="MYLOG" type="com.example.mybatisanalyze.logger.MyloggerImpl"/>
    </typeAliases>

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

<setting name="logImpl" value="MYLOG"/>

通过以上三步就实现了,咱们来看下后果

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

实现原理

日志实现

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

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

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

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

Slf4jLocationAwareLoggerImplSlf4jLoggerImpl是 sfl4j 的两种日志实现类包装,外面还是具体用的 sfl4j 的 Logger 去做事件的,咱们下面的自定义日志实现类就是这么做的。从这里能够看进去,如果咱们没有配置 logImpl,则默认依据程序从你零碎中找第一个有引入的日志包,最终以NoLoggingImpl 兜底,不输入任何日志。

再来看下 logImpl 配置是如何失效的。咱们晓得在启动的时候 mybatis 会去做配置加载,最终加到的全局的 configuration 下,所以从这里咱们能够找到对应的 logImpl 配置项加载

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

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

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

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

洁净打包

咱们在 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 是怎么做的

总结

日志实现尽管比较简单,然而通过这个学习,咱们理解了如何在零碎中做到兼容不同日志实现,在开发工具包的时候如何做到洁净打包。

参考资料

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

退出移动版