欢迎来到HugNew-拥抱变化,扫一扫右边二维码关注微信订阅号:Martin说 或 加QQ群:427697041互相交流,Stay hungry, Stay foolish.

Mybatis Log机制源码分析

J2EE Martin 2890℃ 2评论

1)假设classpath下有如下内容的log4j.properties

请求http://localhost:8080/testoom/test,发现控制台的输出为
DEBUG [http-bio-8080-exec-1] – ooo Using Connection [jdbc:mysql://localhost:3306/test UserName=root@localhost, MySQLDriver]
DEBUG [http-bio-8080-exec-1] – ==> Preparing: select * from application
DEBUG [http-bio-8080-exec-1] – ==> Parameters:
第一行是在org.apache.ibatis.logging.jdbc.ConnectionLogger.ConnectionLogger(Connection conn, Log statementLog)中输出的
第二行是在Object org.apache.ibatis.logging.jdbc.ConnectionLogger.in_voke(Object pro_xy, Method method, Object[] params)throws Throwable中输出的
第三行是在Object org.apache.ibatis.logging.jdbc.PreparedStatementLogger.in_voke(Object pro_xy, Method method, Object[]params) throws Throwable中输出的。

接下来我们详细分析ConnectionLogger(Connection conn, Log statementLog)方法

跟踪isDebugEnabled(),

statementLog是org.apache.ibatis.logging.slf4j.Slf4jImpl的实例,层层深入
org.slf4j.impl.Log4jLoggerAdapter.isDebugEnabled()
org.apache.log4j.Logger.isDebugEnabled()
最后真正的逻辑Category.getEffectiveLevel(),Category是org.apache.log4j.Logger的父类。

查看this的值,如图
inspect-log-hierarchy

注意”cn.javacoder.testoom.mapper”指的是Mapper的namespace的前缀,而不是dao的完整包名的前缀,切记!!

看到这张图,大家一定豁然开朗了。log4j就是按照完整包名来查找日志等级的,越详细优先级越高,在我们的例子中先在”cn.javacoder.testoom.mapper.TestMapper.select”对应的logger对象中匹配,由于我们没有指定日志等级,所以查找它的parent 对象,在本例中parent对象是”log4j.logger.cn.javacoder.testoom.mapper”对应的logger对象,匹配,返回该对象对应的Level. 在这个链当中,最后是RootLogger对象。

再回头看ConnectionLogger.isDebugEnabled()方法,我们刚才分析了”statementLog.isDebugEnabled() || getLog().isDebugEnabled()”的前面一个分支,如果将log4j.logger.cn.javacoder开始的行注释掉,启用log4j.logger.java.sql开始的行,那么就会执行getLog().isDebugEnabled()对应的判断。我们还是按照刚才的方式继续跟踪函数调用,最后我们按照一样的路径到达Category.getEffectiveLevel()方法。
此时this值如图
inspect-log-hierarchy2
先判断”java.sql.Connection”对应的logger对象是否指定了Level对象,没有指定就返回parent RootLogger对应的日志等级,在mybatis中,分别对java.sql.Connection, java.sql.ResultSet, java.sql.Statement, java.sql.PreparedStatem对象进行了封装,这个子类一个重要的任务就是调试日志功能的支持:类图如下:
mybatis-logger-hierarchy
在log4j.Category类中,很多的成员属性都声明为volatile,这引起了我的兴趣。直觉告诉我,logger对象的层级是可以动态改变的,于是决定删除log4j.properties中的所有配置,然后在代码中动态的启用日志等级。
我在TestController.main中打一个断点,然后在Expressions窗口中输入org.apache.log4j.Logger.getLogger(“cn.javacoder.testoom.mapper”)获取Logger 对象,然后如图改变Logger的Level,完美的打印出log;当不需要日志时,将Logger.level设为null,如图:

change-level-danymicly

结束语:

我们既可以通过mapper的namespace来指定哪些SQL需要输出,也可以通过对java.sql.*包的接口指定日志等级为DEBUG来全局的启用输出SQL功能,前缀的优先级大于后者,还可以再运行时动态的启用SQL输出功能。

来源:javacoder.cn

转载请注明:HugNew » Mybatis Log机制源码分析

喜欢 (2)or分享 (0)
发表我的评论
取消评论

表情
(2)个小伙伴在吐槽
  1. 贵站转载我的文档也请写个出处好吧,javacoder.cn
    匿名2015-08-24 09:39 回复
    • sorry,已补上,如有问题随时联系
      Martin2015-08-24 21:05 回复