Mybatis日志设计原理 - 适配器模式

首先我们知道软件设计存在6大基本原则,这并不是仅存在于java中的

而适配器模式就是满足6大原则中的开闭原则,既对扩展开放,对修改关闭。尽量通过扩展来面对需求的更改或者系统的变化,尽量不要对原有内容修改。

 

适配器模式

在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种。在对象适配器模式中,适配器与适配者之间是关联关系,组合关系;在类适配器模式中,适配器与适配者之间是继承关系。在实际开发中,对象适配器的使用频率更高。

适配器模式中包含了三个关键的点

  1. target(目标抽象类):既用户实际需要的类型,可以是一个抽象类或接口,也可以是具体类。
  2. adapter(适配器): 适配器可以调用另一个接口,作为一个转换器,对adaptee和target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承target并组合一个adaptee对象使二者产生联系。
  3. adaptee(适配者):适配者即被适配的角色,它定义了一个已经存在的类型,这个类型需要适配来提供给我们用户所使用,适配者类一般是一个具体类,包含了客户希望用到的方法。

Mybatis的日志体系就是对适配器模式的一个完美的应用,他适配了市面上主流的日志框架,来提供给他自己使用,使这些日志框架的使用方式统一。

Mybatis日志设计原理 - 适配器模式_第1张图片

这是Mybatis中的日志体系

其中的Log接口就是Mybatis中实际需要用到的接口,也就是用户需要的类型,既目标接口。

然后log4j2,log4j这些包就是Mybatis实现的适配器类,用来适配对应的日志框架

对应的日志框架就是适配者,也就是现有的类,我们需要将其适配成Mybatis中需要的Log类型。

 

LogFactory类(截取部分代码)

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

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

private static void setImplementation(Class implClass) {
  try {
    // 尝试初始化对应的适配器,适配器中引入了其他日志框架的API,如果没有导入对应的jar包就会出现异常,导致当前适配器初始化失败
    Constructor 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);
  }
}

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

 其内部存在这样的静态代码块,也就是说该类被初始化的时候,就会尝试着去寻找对应的适配者。

看我们的工程中是否引入了对应的日志框架的jar包,如果我们工程中引入了对应的日志框架的jar包,那么其对应的适配器的构造器就能被正确的获取,随后就能在mybatis中利用适配器来实现日志功能了。

Log4j2的适配器

public class Log4j2Impl implements Log {

  private final Log log;

  public Log4j2Impl(String clazz) {
    // Logger和LogManager是Log4j2中的api
    Logger logger = LogManager.getLogger(clazz);
    
    // 去使用另外两个Log4j2的适配器,这个类只是其一个中介作用
    if (logger instanceof AbstractLogger) {
      log = new Log4j2AbstractLoggerImpl((AbstractLogger) logger);
    } else {
      log = new Log4j2LoggerImpl(logger);
    }
  }

  @Override
  public boolean isDebugEnabled() {
    return log.isDebugEnabled();
  }

  @Override
  public boolean isTraceEnabled() {
    return log.isTraceEnabled();
  }

  @Override
  public void error(String s, Throwable e) {
    log.error(s, e);
  }

  @Override
  public void error(String s) {
    log.error(s);
  }

  @Override
  public void debug(String s) {
    log.debug(s);
  }

  @Override
  public void trace(String s) {
    log.trace(s);
  }

  @Override
  public void warn(String s) {
    log.warn(s);
  }

}

 

你可能感兴趣的:(mybatis,设计模式)