Mybatis技术内幕

Scroll Down

日志

在Java开发中常用的日志框架有Log4j、Log4j2、Apache Commons Log、java.util.logging、slf4j等,这些工具对外的接口不尽相同。为了统一这些工具的接口,Mybatis定义了一套统一的日志接口供上层使用,并为上述常用的日志框架提供了相应的适配器。
适配器模式的主要目的是解决由于接口不能兼容而导致的类无法使用的问题,适配器模式会将需要适配的类转换成调用者能够使用的目标接口。这里先介绍适配器模式中涉及的几个角色,如下所述:

  • 目标接口(target):调用者能够直接使用的接口。
  • 需要适配的类(Adaptee):一般情况下,adaptee类中有真正的业务逻辑,但是其接口不能被调用者直接使用。
  • 适配器(adapter):Adapter实现了Target接口,并包装了一个Adaptee对象。Adapter在实现Target接口中的方法时,会将调用委托给Adaptee对象的相关方法,由Adapter完成具体的业务。

使用适配器模式的好处就是复用现有组件。应用程序需要复用现有的类,但接口不能被该应用程序兼容,则无法直接使用。这种场景下就适合使用适配器模式实现接口的适配,从而完成组件的复用。很明显,适配器模式通过提供Adapter的方式完成接口适配,从而完成程序复用Adaptee的需求,避免修改了Adaptee实现接口,这符合开放-封闭原则。当有新的Adaptee需要被复用时,只要添加新的Adapter即可,这也是符合开放-封闭原则。
在Mybatis的日志模块中,就使用了适配器模式。Mybatis内部调用其日志模块时,使用了其内部接口。但是Log4j、Log4j2、Apache Commons Log、java.util.logging、slf4j等第三方日志组件对外提供的接口各不相同,Mybatis为了集成和复用这些第三方日志组件,在其日志模块中提供了多种Adapter,将这些第三方日志组件对外提供的接口适配成了org.apache.ibatis.logging.Log接口,这样Mybatis内部就可以统一通过org.apache.ibatis.logging.Log接口调用第三方日志组件的功能了。

日志适配器

前面描述的多种第三方日志组件都有各自的Log级别,且都有所不同,例如java.util.logging提供了ALL、FINEST、FINE、CONFIG、INFO、WARING等9种级别,而Log4j2则只有trace、debug、info、warn、error、fatal这6种日志级别。Mybatis统一提供了trace、debug、warn、error四个级别,这基本与主流日志框架的日志级别类似,可以满足绝多大数场景的日志需求。
Mybatis的日志模块位于org.apache.ibatis.logging包中,该模块中通过Log接口定义了日志模块的功能,当然日志适配器也会实现此接口。LogFactory工厂类负责创建对应的日志组件适配器。
在LogFactory类加载时会执行其静态代码块,其逻辑是按序加载并实例化对应的日志组件的适配器,然后使用LogFactory.logConstructor这个静态字段,记录当前使用的第三方日志组件的适配器。

核心处理层

本章主要从Mybatis的初始化,动态SQL语句的解析,结果集的映射,参数解析以及SQL语句的执行等几个方面分析Mybatis的核心处理层。

Mybatis初始化

类似于Spring、Mybatis等灵活性和可扩展性都很高的开源框架都提供了很多配置项,开发人员需要在使用时提供相应的配置信息,实现相应的需求。Mybatis中的配置文件主要有两个,分别是mybaits-config.xml配置文件和映射文件。
现在主流的配置方式除了使用XML配置文件,还会配合注解进行配置。在Mybatis初始化的过程中,除了会读取mybatis-config.xml配置文件以及映射配置文件,还会加载配置文件指定的类,处理类中的注解,创建一些配置对象,最终完成框架中各个模块的初始化。另外,也可以使用Java API的方式对Mybatis进行配置,这种硬编码的配置方式主要用在配置量比较少且配置信息不常变化的场景下。

建造者模式

在Mybatis处理mybatis-config.xml以及映射配置文件时,会在内存中创建相应的配置文件对象,该过程的设计使用建造者模式的相关知识。
建造者模式将一个复杂对象的构建过程与它的表示分离,从而使得同样的构建过程可以创建不同的表示。建造者模式将一个复杂的对象的创建过程分成了一步步简单的步骤,用户只需要了解复杂对象的类型和内容,而无须关注复杂对象的具体构造过程,帮助用户屏蔽掉了复杂对象内部的具体构建细节。
建造者模式中的主要角色如下所述:
1、建造者(Builder)接口:Builder接口用于定于建造者构建产品对象的各部分的行为。
2、具体建造者(ConcreteBuilder)角色:在建造者模式中,直接创建产品对象的是具体建造者。具体建造者类必须实现建造者接口所要求的两类方法:一类是建造方法,另一类是获取构建好的产品对象的方法。
3、导演角色(Director)角色:该角色会通过调用具体的建造者,创建需要的产品对象。
4、产品(Product)角色:产品对象就是用户需要使用的复杂对象。
建造者模式的优点如下:
1、建造者模式中的导演角色并不需要知晓产品类的内部细节,它只能提供需要的信息给建造者,由具体建造者处理这些信息(这个处理过程可能会比较复杂)并完成产品构造,这就使产品对象的上层代码与产品对象的创建过程解耦。
2、建造者模式将复杂产品的创建过程分散到了不同的构造步骤中,这种可以对产品的创建过程实现更加精细的控制,也会使创建过程更加清晰。
3、每个具体的建造者都可以创建出完整的产品对象,而且具体建造者之间是相互独立的,因此系统就可以通过不同的具体建造者,得到不同的产品对象。当有新产品出现时,无须修改原有的代码,只需要添加新的具体建造者即可完成扩展,这符合开放-封闭原则。