源码
如果是你设计一个框架,你的日志系统会怎么设计?是自己实现还是依赖日志门面 slf4j commons-logging jul 或者是直接依赖实现 log4j log4j2 logback stdout 或者是干脆不输出日志。其实还是挺令人头疼的一件事,接下来,我们来看看 Mybatis 这款优秀的 ORM 框架是如何做的。
通过上图可以看到,Log 一共有 7 大实现类:
- StdOutImpl
- Log4jImpl
- NoLoggingImpl
- Jdk14LoggingImpl
- JakartaCommonsLoggingImpl
- Slf4jImpl
- Slf4jLocationAwareLoggerImpl
- Slf4jLoggerImpl
- Log4j2Impl
- Log4j2AbstractLoggerImpl
- Log4j2LoggerImpl
接下来我们就逐个分析每一种实现
StdOutImpl
从名字来看,很容易能够看出这个是通过 JDK 原生的 API System.out.println
来实现的,接下来我们看看源码。
package org.apache.ibatis.logging.stdout;
import org.apache.ibatis.logging.Log;
/**
* @author Clinton Begin
*/
public class StdOutImpl implements Log {
public StdOutImpl(String clazz) {
// Do Nothing
}
@Override
public boolean isDebugEnabled() {
return true;
}
@Override
public boolean isTraceEnabled() {
return true;
}
@Override
public void error(String s, Throwable e) {
System.err.println(s);
e.printStackTrace(System.err);
}
@Override
public void error(String s) {
System.err.println(s);
}
//省略下面部分代码
}
这种实现方式较为简单,就是通过标准的输出流输出到指定的目标位置,默认情况下应该是输出到控制台,当然也可以输出到文件,相信很少有人用这种方式。
Log4jImpl
Log4jImpl 是 Apache 的一个开源项目,它可以通过配置文件灵活的配置日志的输出格式和目的地,也是比较主流的实现方式。同时分为 1.x 和 2.x 版本,但是从 2015年8月5日开始,官方建议使用 2.x 传送门:https://logging.apache.org/log4j/1.2/
On August 5, 2015 the Logging Services Project Management Committee announced that Log4j 1.x had reached end of life. For complete text of the announcement please see the Apache Blog. Users of Log4j 1 are recommended to upgrade to Apache Log4j 2
我们先看 1.x 的实现。
package org.apache.ibatis.logging.log4j;
import org.apache.ibatis.logging.Log;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/**
* @author Eduardo Macarron
*/
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 boolean isDebugEnabled() {
return log.isDebugEnabled();
}
@Override
public boolean isTraceEnabled() {
return log.isTraceEnabled();
}
@Override
public void error(String s, Throwable e) {
log.log(FQCN, Level.ERROR, s, e);
}
//省略下面部分代码
}
由于 Mybatis 本身依赖了 Log4j 所以可以直接使用其 API Logger.getLogger
初始化 Logger 对象。
NoLoggingImpl
顾名思义,这种实现方式就是不使用任何日志输出。
package org.apache.ibatis.logging.nologging;
import org.apache.ibatis.logging.Log;
/**
* @author Clinton Begin
*/
public class NoLoggingImpl implements Log {
public NoLoggingImpl(String clazz) {
// Do Nothing
}
@Override
public boolean isDebugEnabled() {
return false;
}
@Override
public boolean isTraceEnabled() {
return false;
}
@Override
public void error(String s, Throwable e) {
// Do Nothing
}
//省略下面部分代码
}
可以看到,方法里面都是空实现。没有任何日志输出操作。
Jdk14LoggingImpl
这种实现方式也是使用了 JDK 原生的 API 还有另外一种叫法 JUL 它使用了 java.util.logging
包下面的 Logger 对象输出日志。
package org.apache.ibatis.logging.jdk14;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.ibatis.logging.Log;
/**
* @author Clinton Begin
*/
public class Jdk14LoggingImpl implements Log {
private final Logger log;
public Jdk14LoggingImpl(String clazz) {
log = Logger.getLogger(clazz);
}
@Override
public boolean isDebugEnabled() {
return log.isLoggable(Level.FINE);
}
@Override
public boolean isTraceEnabled() {
return log.isLoggable(Level.FINER);
}
@Override
public void error(String s, Throwable e)