实现目的
提供统一的日志接口操作规范,适配7种主流的日志框架
源码package
src/main/java/org/apache/ibatis/logging
使用场景
在Mybatis配置文件中,使用
<settings>
...
<setting name="LogImpl" value="LOG4J"/>
...
</settings>
指定使用LOG4J作为日志框架。
除此之外,从Configuration
类的
setting
节点的value支持7类值,分别对应7种主流的日志框架
适配器模式应用
主要用到了对象适配器模式。针对不同的日志框架提供对Log接口对应的实现。分别支持了
- Apache Common Logging: 使用JCL输出日志
- Log4J2
- Java Util Logging: 使用JDK自带的日志模块
- Log4j
- No Logging: 不输出日志
- SLF4J: 使用SLF4J日志门面模式
- Stdout: 将日志输出到标准输出设备,eg: 控制台 以实现了log4j日志接口Logger到MyBatis日志接口Log的转换类:Log4jImpl为例
- Log4jImpl实现了Log接口,实现Log接口的方法。
public class Log4jImpl implements Log {}
- 持有Logger对象的引用,并且调用Log接口的方法,实际上是通过调用Logger对象的方法实现的。
public class Log4jImpl implements Log {
private static final String FQCN = Log4jImpl.class.getName();
// 适配器模式中需要适配的目标类
private final Logger log;
public Log4jImpl(String clazz) {
log = Logger.getLogger(clazz);
}
@Override
public void error(String s, Throwable e) {
log.log(FQCN, Level.ERROR, s, e);
}
@Override
public void trace(String s) {
log.log(FQCN, Level.TRACE, s, null);
}
...
}
工厂模式的应用
在前面提到了Mybatis通过对象适配器模式支持多种不同的日志输出策略,但实际使用哪种方式输出日志,则采用了
工厂模式来创建(LogFactory
类)。可以通过Mybatis内置的UT LogFactoryTest跟踪该类的实现方式,如:
class LogFactoryTest {
@Test
void shouldUseSlf4j() {
LogFactory.useSlf4jLogging();
Log log = LogFactory.getLog(Object.class);
logSomething(log);
assertEquals(log.getClass().getName(), Slf4jImpl.class.getName());
}
}
通过LogFactory可以创建指定日志框架的实现类,如:
/**
* 使用自定义的日志框架输出日志
*
* @param clazz 日志实现类
*/
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
setImplementation(clazz);
}
/**
* 指定指定日志实现类
*
* @param implClass 日志实现类
*/
private static void setImplementation(Class<? extends Log> implClass) {
try {
// 获取Log实现类的构造器对象
Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
// 创建日志实现类对象
Log log = candidate.newInstance(LogFactory.class.getName());
if (log.isDebugEnabled()) {
log.debug("Logging initialized using '" + implClass + "' adapter.");
}
// 记录当前使用的日志实现类的构造器对象,有且只能有一个
logConstructor = candidate;
} catch (Throwable t) {
throw new LogException("Error setting Log implementation. Cause: " + t, t);
}
}
在Mybatis框架启动时,解析主配置文件中的LogImpl参数后调用Configuration
类的setLogImpl()
方法设置日志的实现类:
/**
* 设置日志实现类
*
* @param logImpl 日志实现类
*/
public void setLogImpl(Class<? extends Log> logImpl) {
if (logImpl != null) {
this.logImpl = logImpl;
// 使用工厂类创建指定的日志实现类,保证整个Mybatis框架只使用一种指定的日志框架
LogFactory.useCustomLogging(this.logImpl);
}
}