第二章 日志模块 适配器模式

作者: Xcdf | 来源:发表于2019-01-19 21:21 被阅读59次

简书 许乐
转载请注明原创出处,谢谢!

  在Java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外接口不尽相同。为了统一这些工具的接口,Mybatis 定义了一套统一的日志接口供上层使用,并分别为上述常用的日志框架提供了相应的适配器。
  适配器模式的主要目的是解决由于接口不能兼容而导致类无法使用的问题,适配器模式会将需要适配的类转换成调用者能够使用的目标接口。
   目标接口(Target): 调用者能够直接使用的接口。需要适配的类(Adaptee):一般情况下,Adaptee类中有真正的业务逻辑,但是其接口不能被调用者直接使用。适配器(Adapter): Adapter 实现了Target接口,并且包装了一个Adaptee对象。Aapter在实现Target接口中的方法时,会将调用委托给Adpatee对象的相关方法,由Adaptee完成具体的业务。
下面是适配器的类图:

适配器类图

  在Mybatis的日志模块中就是使用了适配器模式。Mybatis内部在使用日志模块时,使用了其内部接口 org.apache.ibatis.logging.Log,但是常用的日志框架的对外接口各不相同,Mybatis为了复用和集成这些第三方日志组件,在其日志模块中,提供了多种Adapter,将这些第三方日志组件对外接口适配成org.apache.ibatis.logging.Log,这样Myabtis 就可以通过Log接口调用第三方日志了。

Log 接口(Mybatis提供)

package org.apache.ibatis.logging;
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);    
}

Mybatis 提供了多种常用的日志框架的适配器,以下为Log4j的适配器:

public class Log4jImpl implements Log {
  private final Logger log;  //持有一个org.apache.log4j.Logger的引用
  public Log4jImpl(String clazz) {
    log = Logger.getLogger(clazz);//初始化org.apache.log4j.Logger对象
  }
  //以下方法将请求全部委托给org.apache.log4j.Logger对象
  @Override
  public boolean isDebugEnabled() {
    return log.isDebugEnabled();
  }
  @Override
  public boolean isTraceEnabled() {
    return log.isTraceEnabled();
  }
 //.... 其他级别的日志输出与上述isDebugEnabled和isTraceEnabled类似  
}

LogFactory 工厂类负责创建对应的日志组件适配器

package org.apache.ibatis.logging;

import java.lang.reflect.Constructor;

public final class LogFactory {

//记录当前使用的第三方日志组件所对应的适配器的构造方法
private static Constructor<? extends Log> logConstructor;

static {
    tryImplementation(new Runnable() {
      @Override
      public void run() {
        useSlf4jLogging();
      }
    });
    //...... 其他日志组件
    tryImplementation(new Runnable() {
      @Override
      public void run() {
        useNoLogging();
      }
    });
  }
private static void tryImplementation(Runnable runnable) {
   if(logConstructor == null) {
       try {
         runnable.run();
       } catch (Throwable t) {
        // ignore
       }
   }
}
public static synchronized void useLog4JLogging() {
 // **注意这里的名称为Log4jImpl.class 初始化了Log4j的适配器
 setImplementation(org.apache.ibatis.logging.log4j.Log4jImpl.class);
}
//给logConstructor 赋值
private static void setImplementation(Class<? extends Log> implClass) {
   //... 异常处理代码
   Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
   // ... 省略打日志代码
   logConstructor = candidate;
  }
}
//==============================
//供上层应用调用
public static Log getLog(Class aClass) {
    return getLog(aClass.getName());
}
public static Log getLog(String logger) {
    //...省略异常处理代码
    return logConstructor.newInstance(logger);
}
}

疑问:
1.在静态代码块static{try...}中初始化,为什么传入Runnable对象 ?
2.静态方法"public static synchronized void useLog4JLogging() {"在初始化日志组件时,为什么要加锁?
3.测试加锁的正确性:先将synchronized 去掉,编译打包后,开启多个线程写日志测试正确性。
4.与SLF4J的区别? 是否可以移植logging模块到其他项目中,实现可选的日志主件?

相关文章

  • 第二章 日志模块 适配器模式

    简书 许乐转载请注明原创出处,谢谢!   在Java开发中常用的日志框架有Log4j,Log4j2,Apache ...

  • 常用的Javascript设计模式

    一、构造函数模式 二、工厂模式 三、模块模式 四、混合模式 五、单例模式 六、发布订阅者模式 七、适配器模式适配器...

  • mybatis源码-日志模块-logging

    1.包结构 2.日志模块类图 3.适配器模式 1.mybatis 没有本身的日志实现,使用的都是比较流行的第三方组...

  • 设计模式笔记目录

    1、适配器(Adapter)2、模块方法(Template Method)3、工厂模式(Factory Metho...

  • 结构型模式-适配器模式

    重构时,不修改已有模块,增加适配器来协调2个模块工作 适配器模式: 作为两个不兼容的接口之间的桥梁。它结合了两个独...

  • Java设计模式(二)

    talk is cheap show me the code 适配器模式 类适配器模式 接口适配器模式 对象适配器...

  • 适配器模式

    目录 1、什么是适配器模式? 2、适配器模式结构? 3、如何实现适配器模式? 4、适配器模式的特点? 5、适配器模...

  • 设计模式之适配器模式

    适配器模式: 类适配器模式、对象适配器模式、接口适配器模式 1.类适配器模式:新的接口出现了,但是和老的接口不兼容...

  • 学习iOS设计模式第一章 适配器(Adapter)

    今天学习了iOS设计模式中的适配器模式,适配器有两种模式对象适配器模式-- 在这种适配器模式中,适配器容纳一个它包...

  • 第4章 结构型模式-适配器模式

    一、适配器模式简介 二、适配器模式的优点 三、适配器模式的实例

网友评论

    本文标题:第二章 日志模块 适配器模式

    本文链接:https://www.haomeiwen.com/subject/umttjqtx.html