iBatis使用log4j2输出日志

时间:2021-02-07 21:52:42

原文链接这里

iBatis是一个老项目,2.3.4.726版本发布之后,项目改名为MyBatis,项目主页目前为http://mybatis.github.io/。

我从08年开始接触iBatis,一直使用2.3.4.726版本,直至当前的项目。iBatis恰到好处的满足了项目组在ORM、SQL维护方面的需求,所以也一直懒得换成其它同类开源软件,比如MyBatis。

最近参与新的项目开发,一切都要从零开始。为了节省时间,我直接把原项目中数据库相关操作的代码拿过来使用,发现遇到一个问题。新项目基于log4j2来输出日志,我按照求配置了iBatis相关的日志记录器之后,发现SQL执行时没有任何日志输出。iBatis在日志中输出拼装后的SQL、绑定的变量、查询返回的结果等,这对我来说是极为有用的特性,现在新项目中相关的日志都消失了,那分析SQL的正确性时就只好靠猜了。项目进度比较紧,我一开始没有时间去仔细考虑日志的问题。
好在紧急需求很快就搞定了,我终于有相对充足的时间来解决这个iBatis日志不输出的问题。项目里使用的log4j2配置文件不方便直接贴出来,精简之后如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<logger name="java.sql" level="debug" additivity="false">
<appender-ref ref="Console"/>
</logger>
<root level="debug">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>

根据官网的资料,我反复对比过几次,确认配置文件没有问题,应该是其它地方出了问题。

找到iBatis的源码,打开iBatis创建日志记录器的类com.ibatis.common.logging.LogFactory,这个类是日志记录器的构造器工厂类,有如下的一段代码,用来定义查找日志记录器的顺序。

static
{
tryImplementation("org.apache.commons.logging.LogFactory", "com.ibatis.common.logging.jakarta.JakartaCommonsLoggingImpl");
tryImplementation("org.apache.log4j.Logger", "com.ibatis.common.logging.log4j.Log4jImpl");
tryImplementation("java.util.logging.Logger", "com.ibatis.common.logging.jdk14.Jdk14LoggingImpl");
tryImplementation("java.lang.Object", "com.ibatis.common.logging.nologging.NoLoggingImpl");
}

从这段代码可以看出,iBatis支持四种记录器,分别是:

  • commons-logging
  • apache-log4j
  • JDK原生的Log系统
  • 空记录器,不记录日志

看到这段代码的时候,我秀逗的大脑突然快速转动起来。在之前的项目时,iBatis和log4j配合可以正常输出日志,原因是iBatis针对log4j实现了专门的日志记录器构造工厂;当前的这个项目基于log4j2,iBatis没有专门定制的日志记录器工厂类,所以日志无法正常输出。想到这里,日志不能输出的原因找到了,但怎么让iBatis的日志恢复正常,我踌躇了好久。考虑要不要修改iBatis的源码,仿照com.ibatis.common.logging.log4j.Log4jImpl新写一个新的日志记录器的构造器。犹豫了半天,想想还是算了,我倒是不害怕修改iBatis的源码,之前参与过的一个项目里,已经为了修改另外的问题修改过iBatis的源码,编译环境什么的都还在;为了新项目修改点源码根本不是事情,但是考虑到项目正式发布时可能要做开源软件扫描和整改,我就怂了,还是少给自己找点事情吧。
重新回到iBatis创建日志记录器工厂类的代码,琢磨半天,猜想commons-logging也许是一个突破口。假如能够通过扩展commons-logging的构造工厂来搞定问题的话,项目里不需要增加新的依赖,因为项目的lib目录下已经有commons-logging相关的jar文件了。
感谢CSDN上不知名的热心网友,我找到一份commons-logging的配置说明,按照说明在项目的代码根路径下增加了commons-logging.properties文件,内容如下

org.apache.commons.logging.Log=ibatis.Log4j2Impl

这个ibatis.Log4j2Impl类先占位,具体实现网友的那份说明里没写,唯一了解的信息是类Log4j2Impl需要实现接口org.apache.commons.logging.Log,但如何实现不清楚。好在项目里有一些开源软件使用commons-logging来记录日志,在eclipse里针对org.apache.commons.logging.Log接口按F4,查找当前已实现了接口的类,发现commons-logging自带的org.apache.commons.logging.impl.Jdk14Logger可供参考,所以直接把相关的代码抄到ibatis.Log4j2Impl里,解决掉几个编译问题之后,工厂类就大功告成,接下来就是验证iBatis是否可以正常输出。
基于iBatis写个简单的测试类,代码如下

package ibatis;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public class Test {

private static Logger logger = LogManager.getLogger(Test.class);
public static void main(String[] args) throws Exception {
SqlMapClient sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(Test.class.getClassLoader().getResourceAsStream("sql-map-config.xml"));
logger.info("before query");
sqlMapClient.queryForList("User.selectSubscriberInfo");
logger.info("succeed to query");
}
}

在eclipse里执行这段代码,终于看到了久违的SQL运行日志。