Mybatis的日志是怎么实现随着引入的日志框架改变而改变
Mybatis有自己的日志接口Log和对应的日志创建工厂LogFactory,使用了装饰者模式,底层还是调用原生的日志框架API。
那么他是怎么实现随着引入的日志框架改变而改变的呢?
先来了解下maven项目的dependency元素标签optional的作用。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 防止将devtools依赖传递到其他模块中 -->
</dependency>
假如你的Project A的某个依赖D添加了<optional>true</optional>
,当别人通过pom依赖Project A的时候,D不会被传递依赖进来。
Mybatis的源码中引入了各种的日志依赖包,并且使用<optional>true</optional>
的形式。这样在Mybatis源码中依然可以使用各种日志框架API,但是当我们引入mybatis框架的时候就需要有一个日志依赖导入,不然Mybatis中的日志实现就无法找到对应的类而报异常。可是我们什么日志都没引入的时候,依然没有报异常,这是为什么呢?因为有个org.apache.ibatis.logging.nologging.NoLoggingImpl.class
,优先级最低,只有当框架发现没有引入其他日志框架的时候才会使用,也就是关闭日志。
各日志框架的优先级如下,一旦匹配到一个,下面的就不执行了:
查找的方法如下:
在执行的构造函数中会使用对应原生框架的API初始化,但是如果没有引入依赖的话,就会报出如下的异常
被捕获到之后再按优先级执行下一个日志框架选择。这种自适应框架依赖的实现逻辑确实脑洞大开,反正我是学到了。
SQL执行的日志打印实现方式
如果是池化的数据源,那么第一步从事务对象中拿到的Connection对象其实是一个连接的代理对象,对close方法进行了增强,当调用close方法的时候会将连接对象归还到连接池里。
我们看到如果日志开启了debug模式,那么还会对这个返回的Connection对象做一个代理,如下:
框架在执行这个连接方法的时候,先打印下日志,并且还是返回一个做了日志增强的代理对象。其实这也是AOP的思想