mybatis 日志加载
mybatis 日志处理
为了避免歧义,这里附上分析的版本号
名称 | 版本 |
java | 1.8.0_102 |
mybatis | 3.4.6 |
环境
maven
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
例子
public class LogTest {
public static void main(String[] args) {
org.apache.ibatis.logging.Log log = org.apache.ibatis.logging.LogFactory.getLog(LogTest.class);
log.debug("debug message");
}
}
控制台没有任何输出.
分析加载过程
首先分析 org.apache.ibatis.logging.LogFactory 类加载时调用的静态区域
static {
tryImplementation(() -> {useSlf4jLogging();); tryImplementation(() -> {useCommonsLogging();); tryImplementation(() -> {useLog4J2Logging();); tryImplementation(() -> {useLog4JLogging();); tryImplementation(() -> {useJdkLogging();); tryImplementation(() -> {useNoLogging();); }
按照 slf4j -> commons -> log4j2 -> log4j -> jdklog -> nolog 去加载日志.
名称 | 类别 | 描述 |
slf4j | 接口 | 可以自由配置: log4j,logback,log4j2 等日志实现 |
commons-logging | 接口 | 可以自由配置: log4j,logback,log4j2 等日志实现 |
log4j2 | 实现 | log4j的第二代进化版本 |
log4j | 实现 | log4j第一代 |
jdklog | 接口 | 配置jdk自带的 控制台,文件 或自定义日志 |
nolog | 实现 | 所有日志打印均不作任何操作 |
由于目前没有配置任何和日志有关的信息,所以这里一定会加载到 jdklog
接下来逐步分析每个类型的加载过程
slf4j
public static synchronized void useSlf4jLogging() {
setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
}
private static void setImplementation(Class<? extends Log> implClass) {
try {
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);
}
}
实际上就是创建 new Slf4jImpl(“org.apache.ibatis.logging.LogFactory”);
创建实现类
源码中,是import 的 org.slf4j.Logger。 这里为了便于理解,直接加载类前面
public class Slf4jImpl implements org.apache.ibatis.logging.Log {
private org.apache.ibatis.logging.Log log;
public Slf4jImpl(String clazz) {
org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(clazz);
if (logger instanceof org.slf4j.LocationAwareLogger) {
try {
// check for slf4j >= 1.6 method signature
logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);
log = new org.slf4j.Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger);
return;
} catch (SecurityException e) {
// fail-back to Slf4jLoggerImpl
} catch (NoSuchMethodException e) {
// fail-back to Slf4jLoggerImpl
}
}
// Logger is not LocationAwareLogger or slf4j version < 1.6
log = new org.slf4j.Slf4jLoggerImpl(logger);
}
// 省略其他无关的方法
}
使用适配器模式, 实现 org.apache.ibatis.logging.Log 接口,内部调用 org.slf4j.LoggerFactory.getLogger 的方法
这里分两种情况
- 找到 LoggerFactory 和 Logger 类, 创建代理对象 log = = new org.slf4j.Slf4jLoggerImpl(logger);
- 未找到 LoggerFactory 和 Logger 类, 抛出 java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory, 然后被最顶层的 tryImplementation 捕获后忽略
这里说找到 LoggerFactory 和 Logger 类, 而不是说引入slf4j的jar包,
表示我们可以自己建立这两个类, 来替代实现. (不推荐, 引入jar包就行)
后面的内容都相同,直接附上不同的代理类和代理对象
commons-logging
- 代理类: org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class
- 代理对象: org.apache.commons.logging.Log
log4j
- 代理类: org.apache.ibatis.logging.log4j.Log4jImpl.class
- 代理对象: org.apache.log4j.Logger
log4j2
- 代理类: org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class
- 代理对象: org.apache.logging.log4j.Logger
jdk
- 代理类: org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class
- 代理对象: java.util.logging.Logger
加载流程图
使用
log4j
添加maven配置
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
添加 log4j.properties
log4j.rootLogger=TRACE, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{
2}:%L - %m%n
控制台输出:
11:49:19,636 DEBUG main logging.LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
11:49:19,638 DEBUG main aya.LogTest:6 - debug message
slf4j+log4j12
maven
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.0</version>
</dependency>
log4j-slf4j-impl 2.11.0 会自动引入 slf4j 1.8.0-alpha2 和log4j 2.11.0 的依赖
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
运行程序,控制台输出:
12:19:01.191 [main] DEBUG com.aya.LogTest - debug message
总结
- 自动查找顺序: slf4j -> commons -> log4j2 -> log4j -> jdklog -> nolog
可以在settings 设置 logImpl 指定以下的其中一种,未指定时自动查找
- SLF4J
- LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING
- NO_LOGGING
资料
http://www.mybatis.org/mybatis-3/zh/configuration.html#settings
还没有评论,来说两句吧...