1、spring-jcl介绍
JCL全称:Jakarta Commons Logging
spring-jcl 采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架。
spring 5.1.3版本中支持 LOG4J(2.X及其以上版本) , SLF4J_LAL, SLF4J, JUL
final class LogAdapter {
…
private enum LogApi {
LOG4J, SLF4J_LAL, SLF4J, JUL
}
…
}
2、使用方式:
1、加入具体的日志实现类:LOG4J, SLF4J_LAL, SLF4J, JUL
2、针对某个日志系统加入配置例如:log4j2.xml
3、调用统一api创建日志对象
Log log = LogFactory.getLog(HashMapTest.class);
log.info(map);
3、源码分析
1、LogFactory调用静态方法 getLog,通过适配器LogAdapter返回具体的LOGS对象
public abstract class LogFactory {
…
public static Log getLog(String name) {
return LogAdapter.createLog(name);
}
…
}
2、LogAdapter 静态代码块的方式,根据classpath下具体的日志系统jar包,识别当前系统的日志实现方式,默认使用JUL
private static LogApi logApi = LogApi.JUL;
static {
ClassLoader cl = LogAdapter.class.getClassLoader();
try {
// Try Log4j 2.x API
Class.forName(“org.apache.logging.log4j.spi.ExtendedLogger”, false, cl);
logApi = LogApi.LOG4J;
}
catch (ClassNotFoundException ex1) {
try {
// Try SLF4J 1.7 SPI
Class.forName(“org.slf4j.spi.LocationAwareLogger”, false, cl);
logApi = LogApi.SLF4J_LAL;
}
catch (ClassNotFoundException ex2) {
try {
// Try SLF4J 1.7 API
Class.forName(“org.slf4j.Logger”, false, cl);
logApi = LogApi.SLF4J;
}
catch (ClassNotFoundException ex3) {
// Keep java.util.logging as default
}
}
}
}
3、 LogAdapter.createLog(name); 使用 switch case 方式根据上一步的判断,调用具体的日志适配器,创建具体Log对象,此处以LOG4J为例。
public static Log createLog(String name) {
switch (logApi) {
case LOG4J:
return Log4jAdapter.createLog(name);
case SLF4J_LAL:
return Slf4jAdapter.createLocationAwareLog(name);
case SLF4J:
return Slf4jAdapter.createLog(name);
default:
return JavaUtilAdapter.createLog(name);
}
}
private static class Log4jAdapter {
public static Log createLog(String name) {
return new Log4jLog(name);
}
}
// 对log4j的方法进行包装适配:isFatalEnabled、error、info … 最终调用具体的日志系统方法
private static class Log4jLog implements Log, Serializable {
private static final LoggerContext loggerContext =
LogManager.getContext(Log4jLog.class.getClassLoader(), false);
private final ExtendedLogger logger;
public Log4jLog(String name) {
this.logger = loggerContext.getLogger(name);
}
@Override
public boolean isFatalEnabled() {
return this.logger.isEnabled(Level.FATAL);
}
@Override
public void error(Object message) {
log(Level.ERROR, message, null);
}
@Override
public void info(Object message) {
log(Level.INFO, message, null);
}
}