SLF4J 中的适配器模式
什么是适配器模式
适配器模式中,适配器包装不兼容指定接口的对象,来实现不同兼容指定接口。
SLF4J 中的适配器模式
SLF4J 是一个日志门面系统,其中提供了统一的 Logger 等接口,许多框架都会面向 SLF4J 打印日志,这样就不会和具体的日志框架耦合在一起,框架使用者也就能够很方便地在不同日志实现之间切换。
SLF4J 出现之前,已经有 Log4j 等日志框架了,其本身有一套 Logger 之类的接口,为实现和 SLF4J 兼容,就引入了对应适配器层 slf4j-log4j12。
首先看一下 SLF4J 中的 Logger 接口:
public interface Logger {
String getName();
void debug(String msg);
void info(String msg);
void warn(String msg);
void error(String msg);
// ...省略其他方法
}
而待适配的 Log4j 的 Logger 部分源码如下:
public class Logger extends Category {
protected Logger(String name) {
super(name);
}
public static Logger getLogger(String name) {
return LogManager.getLogger(name);
}
public static Logger getLogger(Class clazz) {
return LogManager.getLogger(clazz.getName());
}
public static Logger getRootLogger() {
return LogManager.getRootLogger();
}
public static Logger getLogger(String name, LoggerFactory factory) {
return LogManager.getLogger(name, factory);
}
public void trace(Object message) {
if (!this.repository.isDisabled(5000)) {
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
this.forcedLog(FQCN, Level.TRACE, message, (Throwable)null);
}
}
}
// ...省略部分方法
}
其继承的 Category 类中有 debug、info 等方法。其核心方法为 log:
public void log(String callerFQCN, Priority level, Object message, Throwable t) {
if(repository.isDisabled(level.level)) {
return;
}
if(level.isGreaterOrEqual(this.getEffectiveLevel())) {
forcedLog(callerFQCN, level, message, t);
}
}
下面再看适配器类 Log4jLoggerAdapter,它先是继承了 MarkerIgnoringBase,MarkerIgnoringBase 实现了 Logger,等于说 Log4jLoggerAdapter 实现了 Logger:
public final class Log4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable {
private static final long serialVersionUID = 6182834493563598289L;
final transient org.apache.log4j.Logger logger;
Log4jLoggerAdapter(org.apache.log4j.Logger logger) {
this.logger = logger;
this.name = logger.getName();
traceCapable = isTraceCapable();
}
public void debug(String msg) {
logger.log(FQCN, Level.DEBUG, msg, null);
}
public void info(String msg) {
logger.log(FQCN, Level.INFO, msg, null);
}
// ...省略部分方法
}
Log4jLoggerAdapter 的构造方法接收 org.apache.log4j.Logger 类型的对象,其 debug 等方法的实现中,将具体的打印工作委托给 Log4j Logger。
如果 Log4j 和 SLF4J 正常整合,则 SLF4J 的 LoggerFactory.getLogger 方法最终会返回 Log4jLoggerAdapter 的实例,从而使 Log4j 和 SLF4J 兼容。
下面是类图: