美文网首页程序员Java
MyBatis 中用了哪些牛逼的设计模式?

MyBatis 中用了哪些牛逼的设计模式?

作者: 喝杯Java润润BUG | 来源:发表于2023-03-27 09:56 被阅读0次

    在 MyBatis 的两万多行的框架源码中,使用了大量的设计模式对工程架构中的复杂场景进行解耦,这些设计模式的巧妙使用是整个框架的精华。

    经过整理,大概有以下设计模式,如下图所示。

    image.png

    创建型模式

    工厂模式

    SqlSessionFactory 的结构如下图所示。

    image.png
    • 工厂模式:简单工厂,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例对象的类型。
    • 场景介绍:SqlSessionFactory 是获取会话的工厂,每次我们使用 Mybatis 操作数据库的时候,都会开启一个新的会话。在会话工厂的实现中负责获取数据源环境配置信息、构建事务工厂、创建操作 SQL 的执行器,并最终返回会话实现类。
    • 同类设计:SqlSessionFactory、ObjectFactory、MapperProxyFactory、DataSourceFactory

    单例模式

    Configuration单例配置类的结构如下图所示。

    image.png
    • 单例模式:是一种创建型模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。
    • 场景介绍:Configuration 就像狗皮膏药一样大单例,贯穿整个会话的生命周期,所以的配置对象;映射、缓存、入参、出参、拦截器、注册机、对象工厂等,都在 Configuration 配置项中初始化。并随着 SqlSessionFactoryBuilder 构建阶段完成实例化操作。
    • 同类场景:ErrorContext、LogFactory、Configuration

    建造者模式

    ResultMap建造者模式的结构如下图所示。

    image.png
    • 建造者模式:使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
    • 场景介绍:关于建造者模式在 Mybatis 框架里的使用,那真是纱窗擦屁股,给你漏了一手。到处都是 XxxxBuilder,所有关于 XML 文件的解析到各类对象的封装,都使用建造者以及建造者助手来完成对象的封装。它的核心目的就是不希望把过多的关于对象的属性设置,写到其他业务流程中,而是用建造者的方式提供最佳的边界隔离。
    • 同类场景:SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder

    类型:结构型模式

    适配器模式

    日志实现类的结构如下图所示。

    image.png
    • 适配器模式:是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。
    • 场景介绍:正是因为有太多的日志框架,包括:Log4j、Log4j2、Slf4J 等等,而这些日志框架的使用接口又都各有差异,为了统一这些日志工具的接口,Mybatis 定义了一套统一的日志接口,为所有的其他日志工具接口做相应的适配操作。
    • 同类场景:主要集中在对日志的适配上,Log 和 对应的实现类,以及在 LogFactory 工厂方法中进行使用。

    代理模式

    代理模式的实现结构如下图所示。

    image.png
    • 代理模式:是一种结构型模式,让你能够提供对象的替代品或其占位符。代理控制着对原对象的访问,并允许在将请求提交给对象前进行一些处理。
    • 场景介绍:不吹牛的讲,没有代理模式,就不会有各类的框架存在。就像 Mybatis 中的 MapperProxy 映射器代理实现类,它所实现的功能就是帮助我们完成 DAO 接口的具体实现类的方法操作,你的任何一个配置的 DAO 接口所调用的 CRUD 方法,都会被 MapperProxy 接管,调用到方法执行器等一系列操作,并返回最终的数据库执行结果。
    • 同类场景:DriverProxy、Plugin、Invoker、MapperProxy

    组合模式

    解析节点类的结构如下图所示。

    image.png
    • 组合模式:是一种结构型设计模式,你可以使用它将对象组合成树状结构,并且能独立使用对象一样使用它们。
    • 场景介绍:在 Mybatis XML 动态的 SQL 配置中,共提供了 9 种(trim/where/set/foreach/if/choose/when/otherwise/bind)标签的使用,让使用者可以组合出各类场景的 SQL 语句。而 SqlNode 接口的实现就是每一个组合结构中的规则节点,通过规则节点的组装完成一颗规则树组合模式的使用。
    • 同类场景:主要体现在对各类 SQL 标签的解析上,以实现 SqlNode 接口的各个子类为主。

    装饰器模式

    二级缓存装饰器的实现结构如下图所示。


    image.png
    • 装饰器模式:是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
    • 场景介绍:Mybatis 的所有 SQL 操作,都是经过 SqlSession 会话调用 SimpleExecutor 简单实现的执行器完成的,而一级缓存的操作也是在简单执行器中处理。那么这里二级缓存因为是基于一级缓存刷新操作的,所以在实现上,通过创建一个缓存执行器,包装简单执行器的处理逻辑,实现二级缓存操作。那么这里用到的就是装饰器模式,也叫俄罗斯套娃模式。
    • 同类场景:主要提前在 Cache 缓存接口的实现和 CachingExecutor 执行器中。

    行为型模式

    模板模式

    SQL 执行模板模式如下图所示。


    image.png
    • 模板模式:是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
    • 场景介绍:只要存在一系列可被标准定义的流程,在流程的步骤大部分是通用逻辑,只有一少部分是需要子类实现的,那么通常会采用模板模式来定义出这个标准的流程。就像 Mybatis 的 BaseExecutor 就是一个用于定义模板模式的抽象类,在这个类中把查询、修改的操作都定义出了一套标准的流程。
    • 同类场景:BaseExecutor、SimpleExecutor、BaseTypeHandler

    策略模式

    多类型处理器策略模式的结构如下图所示。


    image.png
    • 策略模式:是一种行为设计模式,它能定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够互相替换。
    • 场景介绍:在 Mybatis 处理 JDBC 执行后返回的结果时,需要按照不同的类型获取对应的值,这样就可以避免大量的 if 判断。所以这里基于 TypeHandler 接口对每个参数类型分别做了自己的策略实现。
    • 同类场景:PooledDataSource\UnpooledDataSource、BatchExecutor\ResuseExecutor\SimpleExector\CachingExecutor、LongTypeHandler\StringTypeHandler\DateTypeHandler

    迭代器模式

    拆解字段解析实现的结构如下图所示。

    image.png
    • 迭代器模式:是一种行为设计模式,让你能在不暴露集合底层表现形式的情况下遍历集合中所有的元素。
    • 场景介绍:PropertyTokenizer 是用于 Mybatis 框架 MetaObject 反射工具包下,用于解析对象关系的迭代操作。这个类在 Mybatis 框架中使用的非常频繁,包括解析数据源配置信息并填充到数据源类上,以及参数的解析、对象的设置都会使用到这个类。
    • 同类场景:PropertyTokenizer

    总结

    通过梳理,MyBatis 大约运用了 10 种左右设计模式。可以说,复杂且优秀的 ORM 框架源码在设计和实现的过程中都会使用大量的设计模式。

    在解决复杂场景的问题时,需要采用分治、抽象的方法,运用设计模式和设计原则等相关知识,把问题合理切割为若干子问题,以便加以理解和解决。

    学习源码远不是只是为了应付面试,更重要的是学习优秀框架在复杂场景下的解决方案。通过学习这些优秀的方案技术,可以提高对技术设计和实现的理解,扩展编码思维,积累落地经验。只有经过这样长期的积累,我们才更有可能成为优秀的高级工程师和架构师。

    相关文章

      网友评论

        本文标题:MyBatis 中用了哪些牛逼的设计模式?

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