MyBatis源码解析-logging模块 - Go语言中文社区

MyBatis源码解析-logging模块


简述

本文主要说明MyBatis的logging模块是如何适配各种日志组件的,以及为什么MyBatis日志组件的优先加载顺序为sf4j -> commons logging -> log4j2 -> log4j -> jdk logging

适配器模式

MyBatis主要通过适配器模式完成各种日志组件的适配工作,适配器模式是23种设计模式的一种,这里只会做简要的说明,具体去进行学习。
适配器模式主要就是将一个接口转换成客户希望的一个接口,是接口不兼容的类可以一起工作。
在这里插入图片描述

  • 目标接口:Target,该角色把其他类转换为我们期望的接口
  • 被适配者: Adaptee 原有的接口,也是希望被改变的接口
  • 适配器: Adapter, 将被适配者和目标接口组合到一起的类

Logging模块结构

在这里插入图片描述

Log接口就是适配器模式中的Target角色,而每一个子包中则包含有各个Adapter,他们都继承了Log接口。

Log接口

在这里插入图片描述

这里直接贴上Log接口的源码,Log接口的作用,主要就是定义了Adater需要实现的方法,从而来统一在不同的log组件下的异常等级。从Log接口中可以看出Mybatis有trace,warn,debug,error四种等级的日志。

Adater适配器

这里拿commons-logging的适配器来做例子。
在这里插入图片描述

JakartaCommonsLoggingImpl实现了Log接口,在对应的实现方法上,其实就是直接调用了Commons-logging组件的方法。

LogFatory

我们已经有了各个日志组件的适配器了,那么在外部去log的时候怎么确定要哪个适配器呢?这就是LogFatory类的作用,先贴上源码

package org.apache.ibatis.logging;

import java.lang.reflect.Constructor;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 */
public final class LogFactory {

  /**
   * Marker to be used by logging implementations that support markers.
   */
  public static final String MARKER = "MYBATIS";

  private static Constructor<? extends Log> logConstructor;

  static {
    tryImplementation(LogFactory::useSlf4jLogging);
    tryImplementation(LogFactory::useCommonsLogging);
    tryImplementation(LogFactory::useLog4J2Logging);
    tryImplementation(LogFactory::useLog4JLogging);
    tryImplementation(LogFactory::useJdkLogging);
    tryImplementation(LogFactory::useNoLogging);
  }

  private LogFactory() {
    // disable construction
  }

  public static Log getLog(Class<?> aClass) {
    return getLog(aClass.getName());
  }

  public static Log getLog(String logger) {
    try {
      return logConstructor.newInstance(logger);
    } catch (Throwable t) {
      throw new LogException("Error creating logger for logger " + logger + ".  Cause: " + t, t);
    }
  }

  public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
    setImplementation(clazz);
  }

  public static synchronized void useSlf4jLogging() {
    setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
  }

  public static synchronized void useCommonsLogging() {
    setImplementation(org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.class);
  }

  public static synchronized void useLog4JLogging() {
    setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
  }

  public static synchronized void useLog4J2Logging() {
    setImplementation(org.apache.ibatis.logging.log4j2.Log4j2Impl.class);
  }

  public static synchronized void useJdkLogging() {
    setImplementation(org.apache.ibatis.logging.jdk14.Jdk14LoggingImpl.class);
  }

  public static synchronized void useStdOutLogging() {
    setImplementation(org.apache.ibatis.logging.stdout.StdOutImpl.class);
  }

  public static synchronized void useNoLogging() {
    setImplementation(org.apache.ibatis.logging.nologging.NoLoggingImpl.class);
  }

  private static void tryImplementation(Runnable runnable) {
    if (logConstructor == null) {
      try {
        runnable.run();
      } catch (Throwable t) {
        // ignore
      }
    }
  }

  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);
    }
  }

}

首先外部会调用LogFatory的getLog方法,该方法如下:
在这里插入图片描述

可以发现getLog中直接使用logConstrutor来实例化组件的,这个类变量实在静态代码块中被赋值的。
在这里插入图片描述

静态代码中多次调用了tryImplementation方法,调用的顺序,就是Mybatis加载各种Log组件的优先级。
在这里插入图片描述

在tryImplementation中,只要logConstructor不为null,就不会再执行后面的方法。因此可以保证使用log组件的优先级。这里以我们引入的是commons logging为例:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过反射机制,实例化对应的适配器,并赋值给类变量。
至此logging模块的大致流程已经分析完毕。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/solo_jm/article/details/104985007
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢