【简写MyBatis】01-简单映射器

前言

新开一个坑,为了学习一下MyBatis的源码,写代码是次要的,主要为了吸收一下其中的思想和手法。

目的

关联对象接口和映射类的问题,把 DAO 接口使用代理类,包装映射操作。

知识点

  1. 动态代理
  2. 简单工厂模式
  3. InvocationHandler接口的使用

实现

既然是简易的MyBatis编写,那肯定得看下源码了;先来一波回忆,MyBatis的使用:

忘记的朋友可以看下之前写的MyBatis手册: https://blog.csdn.net/weixin_43908900/article/details/129780085

https://www.cnblogs.com/xbhog/p/17258782.html

@Test
public void testMybatis(){
    //加载核心配置文件
    try {
        //字符流加载配置
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //创建sql连接工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //创建session连接,设置true,默认提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //反射获取类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userAll = mapper.getUserAll();
        System.out.println(userAll);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

代码中可以看到,接口和映射器有关系的地方应该是sqlSession.getMapper(UserMapper.class);点进去。

先看映射器工厂类:MapperProxyFactory

这部分就是我们本次实现的地方。

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();

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

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethodInvoker> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

简易映射器类图:

MapperProxy代理类来代理需要使用的接口,为了方便后续的维护扩展,在代理类上加一层代理工厂类MapperProxyFactory

使用代理类的好处是: 动态代理允许 MyBatis 在不修改接口实现的情况下,为接口方法提供自定义的行为。这意味着开发者只需要定义接口和 SQL 映射,而无需编写接口的实现类。这种设计促进了关注点分离,使得数据访问逻辑(SQL)与业务逻辑更加清晰,MapperProxy 能够在运行时将 SQL 语句与接口方法动态绑定,这样,MyBatis 可以根据接口方法的签名和注解或 XML 配置来执行相应的 SQL 操作。

使用简单工厂模式的好处: 实现代码复用和模块化,对代理逻辑和接口使用解耦,灵活性高,不改变公共接口等。

总之都是为了项目的高度灵活、扩展、复用等。

通过上述的分析,现在进行代码编写的流程比较明朗了。

代理类的实现:

public class MapperProxy<T> implements InvocationHandler, Serializable {

    private static final long serialVersionUID = -6424540398559729838L;
    //模拟SqlSession
    private Map<String, String> sqlSession;
    private final Class<T> mapperInterface;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //检查一个方法是否来自特定的类或者是一系列接口中的一个
        //是Object自身的方法,就没必要代理,直接调用就行
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        } else {
            //需要匹配的是类名+方法名
            return "你的被代理了!" + sqlSession.get(mapperInterface.getName() + "." + method.getName());
        }
    }

}

映射器代理工厂实现:

public class MapperProxyFactory<T> {

    private final Class<T> mapperInterface;

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

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

}

执行流程如下:

测试

public void testApp() {
    MapperProxyFactory<IUserDao> proxyFactory = new MapperProxyFactory<>(IUserDao.class);
    Map<String,String> sqlSession = new HashMap<>();
    sqlSession.put("com.xbhog.IUserDao.getUserName","模拟执行 Mapper.xml 中 SQL 语句的操作:查询用户姓名");
    IUserDao userDao = proxyFactory.newInstance(sqlSession);
    String userName = userDao.getUserName("100001");
    System.out.println(userName);
}

总结

  1. 通过追溯MyBatis中的源码,明确本文的主要的内容
  2. 明确目标类的依赖关系
  3. 代码实现简易效果
  4. 明确执行流程
  5. 测试代码,符合预期结果

参考&学习

https://mp.weixin.qq.com/s/G3fZES2FvNQK8JLnd9Hx9w

AI大模型辅助

MyBatis源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/390358.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web APIs -05

js执行机制 js是单线程&#xff0c;同一个时间只能做一件事情&#xff0c;所有任务需要排队所以有时候会渲染不连贯 同步任务 都在主线程上执行&#xff0c;形成一个执行栈 异步任务 js的异步是通过回调函数实现的分为三类&#xff1a;1.普通事件&#xff1a;click等&…

课时31:内容格式化_输出格式化_printf格式化

1.1.3 printf格式化 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 场景需求 虽然我们能够通过 echo的方式实现信息某种程度的格式化输出&#xff0c;但是很多信息的输出偏重于手工的干预&#xff0c;效率太慢。我们需要一种功能…

“构建安全高效的前端权限控制系统:确保用户访问合适的内容“

✨✨ 欢迎大家来到喔的嘛呀的博客✨✨ &#x1f388;&#x1f388;希望这篇博客对大家能有帮助&#x1f388;&#x1f388; ✨✨ 一个正在努力的人&#xff0c;期待您的关注✨✨ 目录 引言 一、背景介绍 二 、具体实现方法 &#xff08;1&#xff09;用户角色管理 1. 安装依…

FL Studio21.2水果软件官方中文版网站

FL Studio 21&#xff0c;通常被称为“水果”音乐制作软件&#xff0c;是一款功能强大的数字音频工作站&#xff08;DAW&#xff09;。这款软件起源于“Fruity Loops”&#xff0c;最初的设计初衷是针对采样循环操作&#xff0c;自1998年发布以来&#xff0c;它已经从一款针对M…

Rust中不可变变量与const有何区别?

Rust作者认为变量默认应该是immutable&#xff0c;即声明后不能被改变的变量。这一点是让跨语言学习者觉得很别扭&#xff0c;不过这一点小的改变带来了诸多好处&#xff0c;本节我们来学习Rust的变量。 什么是变量&#xff1f; 如果你初次学习编程语言&#xff0c;变量会是一…

stm32:pwm output模块,记录一下我是用smt32,输出pwm波的记录--(实现--重要)

我是实现了输出pwm波&#xff0c;频率固定&#xff0c;占空比可以不断调整的方法&#xff0c;将PA0接到示波器上&#xff0c;可以看到是一个标准的PWM波&#xff0c;如图下面示波器图。 1&#xff0c;首先是ioc的配置 我刚开始设置的分频的倍数是7199&#xff0c;使得分频的太…

【项目实现】自主HTTP服务器

自主HTTP服务器 项目介绍网络协议栈介绍协议分层 数据的封装与分用数据的封装与分用 HTTP相关知识介绍HTTP的特点 URL格式URI、URL、URNHTTP的协议格式HTTP的请求方法HTTP的状态码HTTP常见的Header CGI机制介绍CGI机制的概念CGI机制的实现步骤CGI机制的意义 日志编写套接字相关…

嵌入式内核链表list_head,如何管理不同类型节点的实现

在Linux内核中&#xff0c;提供了一个用来创建双向循环链表的结构 list_head。虽然linux内核是用C语言写的&#xff0c;但是list_head的引入&#xff0c;使得内核数据结构也可以拥有面向对象的特性&#xff0c;通过使用操作list_head 的通用接口很容易实现代码的重用&#xff0…

NBlog个人博客部署过程记录 -- 后端springboot + 前端vue

项目是fork的Naccl大佬NBlog项目&#xff0c;页面做的相当漂亮&#xff0c;所以选择了这个。可以参考2.3的效果图 惭愧&#xff0c;工作两年了也每个自己的博客系统&#xff0c;趁着过年时间&#xff0c;开始搭建一下. NBlog原项目的github链接&#xff1a;Naccl/NBlog: &#…

问题:人的安全知识和技能是天生的。() #媒体#知识分享#学习方法

问题&#xff1a;人的安全知识和技能是天生的。&#xff08;) 人的安全知识和技能是天生的。() 参考答案如图所示 问题&#xff1a;&#xff08;&#xff09;是党和国家的根本所在、命脉所在&#xff0c;是全国各族人民的利益所在、幸福所在。 A.人民当家作主 B.坚持和完善…

机器学习 day38(有放回抽样、随机森林算法)

有放回抽样 有放回抽样和无放回抽样的区别&#xff1a;有放回可以确保每轮抽取的结果不一定相同&#xff0c;无放回则每轮抽取的结果都相同 在猫狗的例子中&#xff0c;我们使用”有放回抽样“来抽取10个样本&#xff0c;并组合为一个与原始数据集不同的新数据集&#xff0c;虽…

CSS篇--transform

CSS篇–transform 使用transform属性实现元素的位移、旋转、缩放等效果 位移 // 语法 transform:translate(水平移动距离&#xff0c;垂直移动距离) translate() 如果只给一个值&#xff0c;表示x轴方法移动距离 单独设置某个方向的移动距离&#xff1a;translateX() transla…

心理辅导|高校心理教育辅导系统|基于Springboot的高校心理教育辅导系统设计与实现(源码+数据库+文档)

高校心理教育辅导系统目录 目录 基于Springboot的高校心理教育辅导系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、学生功能模块的实现 &#xff08;1&#xff09;学生登录界面 &#xff08;2&#xff09;留言反馈界面 &#xff08;3&#xff09;试卷列表界…

TiDB 在医疗保障信息平台的应用实践

文章介绍了 TiDB 在医疗保障信息平台中的应用。东软医保云应用管理平台通过与 TiDB 联合&#xff0c;成功满足了医疗保障业务中高并发、实时性和复杂查询的要求。在某地市医疗保障信息平台的实践中&#xff0c;TiDB 分布式数据库有效实现了在线交易和实时分析服务&#xff0c;日…

人工智能学习与实训笔记(二):神经网络之图像分类问题

目录 四、图像分类问题 4.1 尝试使用全连接神经网络 4.2 引入卷积神经网络 4.3 分类函数Softmax 4.4 交叉熵损失函数 4.5 学习率优化算法 4.6 图像预处理算法 4.6.1 随机改变亮暗、对比度和颜色等 4.6.2 随机填充 4.6.3 随机裁剪 4.6.4 随机缩放 4.6.5 随机翻转 4.…

阿里云“BGP(多线)”和“BGP(多线)_精品”区别价格对比

阿里云香港等地域服务器的网络线路类型可以选择BGP&#xff08;多线&#xff09;和 BGP&#xff08;多线&#xff09;精品&#xff0c;普通的BGP多线和精品有什么区别&#xff1f;BGP&#xff08;多线&#xff09;适用于香港本地、香港和海外之间的互联网访问。使用BGP&#xf…

基于剪贴板的文件传输方案

文章目录 背景原理步骤获取待上传文件的十六进制数据格式转换输出 背景 某次误删了环境上的C库之后想到的 什么都不可用了&#xff0c;但当前的ssh连接还在&#xff0c;echo命令和重定向符还可以使用 这就催生了我的想法&#xff1a;直接用echo -en “\xab\xcd” > file这样…

人工智能学习与实训笔记(六):百度飞桨套件使用方法

目录 八、百度飞桨套件使用 8.1 飞桨预训练模型套件PaddleHub 8.1.1 一些本机CPU可运行的飞桨预训练简单模型&#xff08;亲测可用&#xff09; 8.1.1.1 人脸检测模型 8.1.1.2 中文分词模型 8.1.2 预训练模型Fine-tune 8.2 飞桨开发套件 8.2.1 PaddleSeg - 图像分割 8…

Codeforces Round 926 (Div. 2)(A~C)

A. Sasha and the Beautiful Array 分析&#xff1a;说实话&#xff0c;打比赛的时候看到这题没多想&#xff0c;过了一下样例发现将数组排序一下就行&#xff0c;交了就过了。刚刚写题解反应过来&#xff0c;a2-a1a3-a2.....an-a(n-1) an - a1&#xff0c;所以最后结果只取决…

MIT-BEVFusion系列八--onnx导出1 综述及相机网络导出

目录 综述export-camera.py加载模型加载数据生成需要导出成 onnx 的模块Backbone 模块VTransform 模块 生成 onnx使用 pytorch 原生的伪量化计算方法导出 camera.backbone.onnx导出 camera.vtransform.onnx 综述 bevfusion的各个部分的实现有着鲜明的特点&#xff0c;并且相互…