mybatis 日志加载

墨蓝 2022-05-20 03:07 178阅读 0赞

mybatis 日志处理

为了避免歧义,这里附上分析的版本号
















名称 版本
java 1.8.0_102
mybatis 3.4.6

环境

maven

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.4.6</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>junit</groupId>
  8. <artifactId>junit</artifactId>
  9. <version>4.12</version>
  10. </dependency>

例子

  1. public class LogTest {
  2. public static void main(String[] args) {
  3. org.apache.ibatis.logging.Log log = org.apache.ibatis.logging.LogFactory.getLog(LogTest.class);
  4. log.debug("debug message");
  5. }
  6. }

控制台没有任何输出.

分析加载过程

首先分析 org.apache.ibatis.logging.LogFactory 类加载时调用的静态区域

  1. static {
  2. 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

  1. public static synchronized void useSlf4jLogging() {
  2. setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
  3. }
  4. private static void setImplementation(Class<? extends Log> implClass) {
  5. try {
  6. Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
  7. Log log = candidate.newInstance(LogFactory.class.getName());
  8. if (log.isDebugEnabled()) {
  9. log.debug("Logging initialized using '" + implClass + "' adapter.");
  10. }
  11. logConstructor = candidate;
  12. } catch (Throwable t) {
  13. throw new LogException("Error setting Log implementation. Cause: " + t, t);
  14. }
  15. }

实际上就是创建 new Slf4jImpl(“org.apache.ibatis.logging.LogFactory”);

创建实现类

源码中,是import 的 org.slf4j.Logger。 这里为了便于理解,直接加载类前面

  1. public class Slf4jImpl implements org.apache.ibatis.logging.Log {
  2. private org.apache.ibatis.logging.Log log;
  3. public Slf4jImpl(String clazz) {
  4. org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(clazz);
  5. if (logger instanceof org.slf4j.LocationAwareLogger) {
  6. try {
  7. // check for slf4j >= 1.6 method signature
  8. logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);
  9. log = new org.slf4j.Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger);
  10. return;
  11. } catch (SecurityException e) {
  12. // fail-back to Slf4jLoggerImpl
  13. } catch (NoSuchMethodException e) {
  14. // fail-back to Slf4jLoggerImpl
  15. }
  16. }
  17. // Logger is not LocationAwareLogger or slf4j version < 1.6
  18. log = new org.slf4j.Slf4jLoggerImpl(logger);
  19. }
  20. // 省略其他无关的方法
  21. }

使用适配器模式, 实现 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包就行)

后面的内容都相同,直接附上不同的代理类和代理对象

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

加载流程图

mybatis日志流程图

使用

log4j

添加maven配置

  1. <dependency>
  2. <groupId>log4j</groupId>
  3. <artifactId>log4j</artifactId>
  4. <version>1.2.17</version>
  5. </dependency>

添加 log4j.properties

  1. log4j.rootLogger=TRACE, stdout
  2. log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{
  5. 2}:%L - %m%n

控制台输出:

  1. 11:49:19,636 DEBUG main logging.LogFactory:135 - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
  2. 11:49:19,638 DEBUG main aya.LogTest:6 - debug message

slf4j+log4j12

maven

  1. <dependency>
  2. <groupId>org.apache.logging.log4j</groupId>
  3. <artifactId>log4j-slf4j-impl</artifactId>
  4. <version>2.11.0</version>
  5. </dependency>

log4j-slf4j-impl 2.11.0 会自动引入 slf4j 1.8.0-alpha2 和log4j 2.11.0 的依赖

log4j2.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration status="DEBUG">
  3. <Appenders>
  4. <Console name="Console" target="SYSTEM_OUT">
  5. <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
  6. </Console>
  7. </Appenders>
  8. <Loggers>
  9. <Root level="DEBUG">
  10. <AppenderRef ref="Console"/>
  11. </Root>
  12. </Loggers>
  13. </Configuration>

运行程序,控制台输出:

  1. 12:19:01.191 [main] DEBUG com.aya.LogTest - debug message

总结

  1. 自动查找顺序: slf4j -> commons -> log4j2 -> log4j -> jdklog -> nolog

可以在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

发表评论

表情:
评论列表 (有 0 条评论,178人围观)

还没有评论,来说两句吧...

相关阅读