为了避免歧义,这里附上分析的版本号
名称 | 版本 |
java | 1.8.0_102 |
mybatis | 3.4.6 |
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
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
接下来逐步分析每个类型的加载过程
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 的方法
这里分两种情况
1. 找到 LoggerFactory 和 Logger 类, 创建代理对象 log = = new org.slf4j.Slf4jLoggerImpl(logger);
2. 未找到 LoggerFactory 和 Logger 类, 抛出 java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory, 然后被最顶层的 tryImplementation 捕获后忽略
这里说找到 LoggerFactory 和 Logger 类, 而不是说引入slf4j的jar包,
表示我们可以自己建立这两个类, 来替代实现. (不推荐, 引入jar包就行)
后面的内容都相同,直接附上不同的代理类和代理对象
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
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
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j-implartifactId>
<version>2.11.0version>
dependency>
log4j-slf4j-impl 2.11.0 会自动引入 slf4j 1.8.0-alpha2 和log4j 2.11.0 的依赖
<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
可以在settings 设置 logImpl 指定以下的其中一种,未指定时自动查找
1. SLF4J
2. LOG4J
3. LOG4J2
4. JDK_LOGGING
5. COMMONS_LOGGING
6. STDOUT_LOGGING
7. NO_LOGGING
http://www.mybatis.org/mybatis-3/zh/configuration.html#settings