聊聊Mybatis的日志模块的适配器模式

举报
周杰伦本人 发表于 2022/08/30 09:53:47 2022/08/30
【摘要】 聊聊Mybatis的日志模块的适配器模式我们在开发中日志是必不可少的一部分,而市场中有很多日志框架供我们使用,mybatis作为一个开源框架需要兼容这些框架,mybatis用了适配器模式来兼容这些框架,适配器模式就是通过组合的方式,将需要适配的类转为使用者能够使用的接口下面咱们分析一下mybatis的日志模块mybatis定义了自己的Log接口 Log接口下面是Log接口的定义:publi...

聊聊Mybatis的日志模块的适配器模式

我们在开发中日志是必不可少的一部分,而市场中有很多日志框架供我们使用,mybatis作为一个开源框架需要兼容这些框架,mybatis用了适配器模式来兼容这些框架,适配器模式就是通过组合的方式,将需要适配的类转为使用者能够使用的接口

下面咱们分析一下mybatis的日志模块

mybatis定义了自己的Log接口

Log接口

下面是Log接口的定义:

public interface Log {

  boolean isDebugEnabled();

  boolean isTraceEnabled();

  void error(String s, Throwable e);

  void error(String s);

  void debug(String s);

  void trace(String s);

  void warn(String s);

}

Log接口中定义了一些常用的方法,比如出入错误日志、debug日志、警告日志和判断是否开启了debug模块和是否开启了跟踪模式

日志工厂类LogFactory

下面再介绍一下生成Log的工厂类
LogFactory的静态代码块加载对应是日志适配器:

    static {
        tryImplementation(LogFactory::useSlf4jLogging);
        tryImplementation(LogFactory::useCommonsLogging);
        tryImplementation(LogFactory::useLog4J2Logging);
        tryImplementation(LogFactory::useLog4JLogging);
        tryImplementation(LogFactory::useJdkLogging);
        tryImplementation(LogFactory::useNoLogging);
    }
    
    private static void tryImplementation(Runnable runnable) {
        if (logConstructor == null) {
            try {
                runnable.run();
            } catch (Throwable t) {
                // ignore
            }
        }
    }
    public static synchronized void useLog4JLogging() {
        setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
    }
   

当logConstructor用来记录日志适配器的构造方法,当logConstructor不为空的时候就不再加载其他的日志适配器了。

接着我们再分析一下setImplementation()方法:

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);
        }
    }
  1. 获取适配器的构造方法
  2. 然后获取这个适配器的实例,如果获取成功,把它的构造方法记录在logConstructor中,否则就会抛出异常

下面就分析一下Log4jImpl类:

Log接口的实现类

Log的实现类有很多,我们这里分析一下它的Log4jImpl实现类

public class Log4jImpl implements Log {

  private static final String FQCN = Log4jImpl.class.getName();

  private final Logger log;

  public Log4jImpl(String clazz) {
    log = Logger.getLogger(clazz);
  }

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

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

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

  @Override
  public void error(String s) {
    log.log(FQCN, Level.ERROR, s, null);
  }

  @Override
  public void debug(String s) {
    log.log(FQCN, Level.DEBUG, s, null);
  }

  @Override
  public void trace(String s) {
    log.log(FQCN, Level.TRACE, s, null);
  }

  @Override
  public void warn(String s) {
    log.log(FQCN, Level.WARN, s, null);
  }

}

Log4jImpl是一个适配器类,它实现了Mybatis自定义的Log接口,它的成员变量Logger是log4j里的类,我们要做的是调用Log接口的方法就可以使用log4j,Logger是需要我们适配的类,因此我们在实现Log接口的方法的时候调用Logger中的方法来完成适配,这就是适配器模式的实现

总结

Mybatis日志模块用到了适配器模式,Log接口是目标接口,Logger等各种日志框架的类是需要我们适配的类,而是适配器是Log4jImpl、Slf4jImpl等适配类

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。