【面试精讲】MyBatis设计模式及源码分析,MyBatis设计模式实现原理

【面试精讲】MyBatis设计模式及源码分析,MyBatis设计模式实现原理

目录

本文导读

一、MyBatis中运用的设计模式详解

[1. 工厂模式(Factory Pattern)](#1. 工厂模式(Factory Pattern))

[2. 单例模式(Singleton Pattern)](#2. 单例模式(Singleton Pattern))

[3. 建造者模式(Builder Pattern)](#3. 建造者模式(Builder Pattern))

[4. 代理模式(Proxy Pattern)](#4. 代理模式(Proxy Pattern))

[5. 模板方法模式(Template Method Pattern)](#5. 模板方法模式(Template Method Pattern))

[6. 策略模式(Strategy Pattern)](#6. 策略模式(Strategy Pattern))

[7. 观察者模式(Observer Pattern)](#7. 观察者模式(Observer Pattern))

二、MyBatis设计模式的源码实现原理

[工厂模式的应用 - SqlSessionFactory](#工厂模式的应用 - SqlSessionFactory)

[单例模式的应用 - SqlSessionFactory](#单例模式的应用 - SqlSessionFactory)

[代理模式的应用 - Mapper动态代理](#代理模式的应用 - Mapper动态代理)

[建造者模式(Builder Pattern)](#建造者模式(Builder Pattern))

[策略模式 - Strategy Pattern](#策略模式 - Strategy Pattern)

[观察者模式 - Observer Pattern](#观察者模式 - Observer Pattern)

三、MyBatis源码解析

[工厂模式 - SqlSessionFactoryBuilder](#工厂模式 - SqlSessionFactoryBuilder)

[单例模式 - SqlSessionFactory](#单例模式 - SqlSessionFactory)

[代理模式 - MapperProxyFactory](#代理模式 - MapperProxyFactory)

总结

博主v:XiaoMing_Java


本文导读

MyBatis是一个流行的持久层框架,它极大地简化了数据库操作,提升了开发效率。在其底层实现中,MyBatis广泛采用了各种设计模式,这些设计模式不仅增加了框架的灵活性和可维护性,也为开发人员提供了丰富的使用场景和扩展能力。本文将深入探讨MyBatis所应用的主要设计模式及其在框架中的具体应用。

一、MyBatis中运用的设计模式详解

1. 工厂模式(Factory Pattern)

工厂模式是一种创建型模式,它提供了一种创建对象的最佳方式。在MyBatis中,SqlSessionFactoryBuilderSqlSessionFactory等关键组件的创建过程就运用到了工厂模式。尤其是SqlSessionFactory的创建,它是通过SqlSessionFactoryBuilder读取MyBatis配置文件并构建出SqlSessionFactory实例。这样做可以隔离复杂的初始化过程,使用户只需关注最终产出,而无需了解创建实例的复杂过程。

2. 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点。在MyBatis中,SqlSessionFactory的设计就是单例模式的经典应用。一旦通过SqlSessionFactoryBuilder创建了SqlSessionFactory实例后,该实例就会在应用程序中被复用,避免了重复创建实例带来的资源浪费。

3. 建造者模式(Builder Pattern)

建造者模式旨在将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。MyBatis中的XMLConfigBuilderXMLMapperBuilder等类的设计采用了建造者模式。这些Builder类负责解析MyBatis的配置文件和映射文件,逐步构建出配置信息和映射信息。通过建造者模式,MyBatis将复杂的解析过程分解成一系列的步骤,使得代码更加清晰和易于维护。

4. 代理模式(Proxy Pattern)

代理模式为其他对象提供一个代理以控制对这个对象的访问。MyBatis中对Mapper接口的实现就是基于JDK动态代理机制。当调用Mapper接口的方法时,实际上是由MyBatis生成的代理类去执行。这种方式允许MyBatis在执行Mapper方法前后插入自定义逻辑,如开启事务、处理缓存等,从而大幅提升了灵活性和可扩展性。

5. 模板方法模式(Template Method Pattern)

模板方法模式定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。MyBatis的BaseExecutor类就是一个模板方法模式的例证。它定义了数据库操作的基本流程,如查询、更新、提交事务等,而具体的执行逻辑则留给其子类(比如SimpleExecutorBatchExecutor等)去实现。这样做的好处是复用了代码,同时又保留了灵活性。

6. 策略模式(Strategy Pattern)

策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。MyBatis中的缓存策略、加载策略等正是策略模式的应用。例如,MyBatis允许用户配置不同的缓存实现(如EHCache、OSCache等),并在运行时根据配置动态选择。这种模式使得MyBatis具有很高的灵活性和扩展性。

7. 观察者模式(Observer Pattern)

观察者模式定义了一种依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在MyBatis中,Configuration对象就是一个观察者,它会监听映射文件的解析事件,并在解析完成后更新自己的状态。通过观察者模式,MyBatis能够动态响应配置信息的变化,增强了框架的动态性和灵活性。

以上便是MyBatis中常见的几种设计模式及其应用。这些设计模式的运用大大提升了MyBatis的内聚性、可扩展性和灵活性,使得MyBatis成为了Java领域广泛使用的ORM框架之一。

二、MyBatis设计模式的源码实现原理

在第一部分中,我们讨论了MyBatis使用的一些关键设计模式及其作用。现在,我们将深入探索这些设计模式在MyBatis源码中的具体实现原理。

工厂模式的应用 - SqlSessionFactory

实现原理:

SqlSessionFactory的创建是通过SqlSessionFactoryBuilder完成的。这个过程遵循了典型的工厂模式设计,SqlSessionFactoryBuilder充当工厂的角色,负责生产SqlSessionFactory对象。

java 复制代码
public SqlSessionFactory build(Reader reader) {
    // 使用XMLConfigBuilder解析配置文件
    XMLConfigBuilder parser = new XMLConfigBuilder(reader, null, null);
    return build(parser.parse());
}

在上述代码中,build方法首先通过XMLConfigBuilder解析给定的配置文件,然后根据解析结果构建出一个SqlSessionFactory实例。这个过程封装了对象的创建逻辑,使得客户端代码无需直接与对象的创建细节打交道。

单例模式的应用 - SqlSessionFactory

实现原理:

在MyBatis中,通常我们会将SqlSessionFactory作为单例存在,以保证全局只有一个数据库连接池,从而节省资源。、

java 复制代码
public class MyBatisUtil {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}

在这段代码中,利用静态初始化块加载配置并创建SqlSessionFactory,确保了其单例性。此外,通过提供一个静态方法getSqlSessionFactory来全局访问该实例,进一步体现了单例模式的特点。

代理模式的应用 - Mapper动态代理

实现原理:

MyBatis中对Mapper接口的实现是基于JDK动态代理的。当调用Mapper接口的方法时,实际上是委托给了由MyBatis动态生成的代理类。

java 复制代码
public class MapperProxy<T> implements InvocationHandler {

    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法调用的处理逻辑
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }
        // 执行SQL操作
        return sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());
    }
}
建造者模式(Builder Pattern)

MyBatis在处理配置文件时,使用了建造者模式。XMLConfigBuilderXMLMapperBuilder是两个具体的例子,它们负责解析MyBatis的配置文件和映射文件。

实现原理: 这段代码展示了BaseExecutor中的query方法,这是一个模板方法,它定义了执行查询的基本流程,并将具体的查询逻辑委托给doQuery方法。子类需要根据不同的需求实现doQuery方法,比如SimpleExecutorReuseExecutor等都有各自的实现,这正是模板方法模式的典型应用。

java 复制代码
public class XMLConfigBuilder extends BaseBuilder {
    private boolean parsed;
    private final XPathParser parser;

    public XMLConfigBuilder(InputStream inputStream) {
        this(new XPathParser(inputStream, true, null));
    }

    public Configuration parse() {
        if (parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true;
        // 省略解析过程...
        return configuration;
    }
}
策略模式 - Strategy Pattern

MyBatis的缓存策略使用了策略模式。MyBatis允许用户选择或自定义缓存实现,这是通过将缓存行为抽象成接口,并允许动态设置具体实现来实现的。

实现原理: Cache接口定义了缓存的行为,而PerpetualCache提供了Cache接口的一个基础实现。MyBatis还支持更多缓存实现,如OSCache、Ehcache等,开发人员可以根据需要选择或自定义缓存策略,这体现了策略模式的灵活性。

java 复制代码
public interface Cache {
    void putObject(Object key, Object value);
    Object getObject(Object key);
    // 更多方法...
}

public class PerpetualCache implements Cache {
    private Map<Object, Object> cache = new HashMap<>();

    @Override
    public void putObject(Object key, Object value) {
        cache.put(key, value);
    }

    @Override
    public Object getObject(Object key) {
        return cache.get(key);
    }
    // 实现其他方法...
}
观察者模式 - Observer Pattern

MyBatis利用观察者模式来实现插件功能。插件可以在MyBatis操作数据库的关键节点被插入,比如执行查询之前。这种机制使得用户能够在不修改MyBatis核心代码的情况下,扩展其功能。

实现原理:Interceptor接口定义了插件需要实现的intercept方法。SomePlugin是一个具体的插件实现,它可以在方法调用前后执行额外的逻辑。这种方式使得MyBatis能够在运行时灵活地扩展功能,体现了观察者模式的特点。

java 复制代码
public interface Interceptor {
    Object intercept(Invocation invocation) throws Throwable;
    // 更多方法...
}

public class SomePlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 在执行前后添加额外的操作
        Object returnObject = invocation.proceed();
        // 在执行后处理
        return returnObject;
    }
}

三、MyBatis源码解析

深入探讨MyBatis的源码对于理解其设计模式的应用至关重要。由于篇幅限制,我们将通过几个关键组件的源码片段来揭示MyBatis是如何实现上文提到的设计模式的。请注意,下面的代码是简化版本,旨在帮助理解其核心原理。

工厂模式 - SqlSessionFactoryBuilder

MyBatis通过SqlSessionFactoryBuilder创建SqlSessionFactory的过程是工厂模式的一个典型应用。

java 复制代码
public class SqlSessionFactoryBuilder {
    public SqlSessionFactory build(Reader reader) {
        // 解析配置文件,构建Configuration对象
        XMLConfigBuilder parser = new XMLConfigBuilder(reader);
        Configuration config = parser.parse();

        // 返回SqlSessionFactory实例
        return new DefaultSqlSessionFactory(config);
    }
}
单例模式 - SqlSessionFactory

虽然MyBatis不直接提供SqlSessionFactory的单例实现,但在实际应用中,开发者通常会将其实现为单例模式,以下是一个简单的示例:

java 复制代码
public class MyBatisUtil {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}
代理模式 - MapperProxyFactory

MyBatis使用JDK动态代理为Mapper接口生成代理对象,以便拦截接口方法的调用。

java 复制代码
public class MapperProxy<T> implements InvocationHandler {
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;

    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 省略具体实现
        return sqlSession.selectList(mapperInterface.getCanonicalName() + "." + method.getName());
    }
}

public class MapperProxyFactory<T> {
    private final Class<T> mapperInterface;

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }

    public T newInstance(SqlSession sqlSession) {
        MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface);
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, mapperProxy);
    }
}

总结

每个设计模式的实现都体现了MyBatis设计的巧妙和优雅,通过这些模式的应用,MyBatis成功地将框架的灵活性、可扩展性和维护性提升到了一个新的高度。希望通过这三部分的解析,你能对MyBatis的设计和实现有一个更加深入的理解。

如果本文对你有帮助 欢迎 关注 、点赞**、收藏** 、评论**, 博主才有动力持续创作!!!**

博主v:XiaoMing_Java

📫作者简介:嗨,大家好,我是 小明 ,互联网大厂后端研发专家,2022博客之星TOP3 / 博客专家 / CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网 6 万粉丝博主。


🍅 文末获取联系 🍅 👇🏻 精彩专栏推荐订阅收藏 👇🏻

|------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| 专栏系列(点击解锁) | 学习路线(点击解锁) | 知识定位 |
| 🔥Redis从入门到精通与实战** 🔥** | Redis从入门到精通与实战 | 围绕原理源码讲解Redis面试知识点与实战 |
| 🔥MySQL从入门到精通** 🔥** | MySQL从入门到精通 | 全面讲解MySQL知识与企业级MySQL实战 |
| 🔥计算机底层原理** 🔥** | 深入理解计算机系统CSAPP | 以深入理解计算机系统为基石,构件计算机体系和计算机思维 |
| 🔥计算机底层原理** 🔥** | Linux内核源码解析 | 围绕Linux内核讲解计算机底层原理与并发 |
| 🔥数据结构与企业题库精讲** 🔥** | 数据结构与企业题库精讲 | 结合工作经验深入浅出,适合各层次,笔试面试算法题精讲 |
| 🔥互联网架构分析与实战** 🔥** | 企业系统架构分析实践与落地 | 行业最前沿视角,专注于技术架构升级路线、架构实践 |
| 🔥互联网架构分析与实战** 🔥** | 互联网企业防资损实践 | 互联网金融公司的防资损方法论、代码与实践 |
| 🔥Java全栈白宝书** 🔥** | 精通Java8与函数式编程 | 本专栏以实战为基础,逐步深入Java8以及未来的编程模式 |
| | 深入理解JVM | 详细介绍内存区域、字节码、方法底层,类加载和GC等知识 |
| | 深入理解高并发编程 | 深入Liunx内核、汇编、C++全方位理解并发编程 |
| | Spring源码分析 | Spring核心七IOC/AOP等源码分析 |
| | MyBatis源码分析 | MyBatis核心源码分析 |
| | Java核心技术 | 只讲Java核心技术 |

相关推荐
Amumu121383 分钟前
Js:正则表达式(二)
开发语言·javascript·正则表达式
学嵌入式的小杨同学10 分钟前
STM32 进阶封神之路(三十二):SPI 通信深度实战 —— 硬件 SPI 驱动 W25Q64 闪存(底层时序 + 寄存器配置 + 读写封装)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
熬夜的咕噜猫22 分钟前
MySQL备份与恢复
数据库·oracle
Sgf22724 分钟前
ES8(ES2017)新特性完整指南
开发语言·javascript·ecmascript
Cosolar28 分钟前
LlamaIndex RAG 本地部署+API服务,快速搭建一个知识库检索助手
后端·openai·ai编程
IAUTOMOBILE31 分钟前
Python 流程控制与函数定义:从调试现场到工程实践
java·前端·python
hutengyi31 分钟前
PostgreSQL版本选择
java
皮皮林55137 分钟前
重磅!JetBrains 正式发布全新的 AI 开发工具,定名 AI IDE AIR
java·intellij idea
jnrjian38 分钟前
recover database using backup controlfile until cancel 假recover,真一致
数据库·oracle
RestCloud39 分钟前
API网关 vs iPaaS:企业集成架构选型的本质差异与2026年选型指南
架构·数据处理·数据传输·ipaas·ai网关·集成平台