前言

新开一个坑,为了学习一下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源码

【简写MyBatis】01-简单映射器的更多相关文章

  1. MyBatis实战之映射器

    映射器是MyBatis最强大的工具,也是我们使用MyBatis时用得最多的工具,因此熟练掌握它十分必要.MyBatis是针对映射器构造的SQL构建的轻量级框架,并且通过配置生成对应的JavaBean返 ...

  2. Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    关系型数据库和SQL是经受时间考验和验证的数据存储机制.和其他的ORM 框架如Hibernate不同,MyBatis鼓励开发者可以直接使用数据库,而不是将其对开发者隐藏,因为这样可以充分发挥数据库服务 ...

  3. 【长文】Spring学习笔记(七):Mybatis映射器+动态SQL

    1 概述 本文主要讲述了如何使用MyBatis中的映射器以及动态SQL的配置. 2 MyBatis配置文件概览 MyBatis配置文件主要属性如下: <settings>:相关设置,键值对 ...

  4. 第六章 mybatis注入映射器

    为了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 编写数据访问对象 (DAO)的代码,MyBatis-Spring 提供了一个动态代理的实现:Map ...

  5. SpringMVC中注解和非注解方式下的映射器和适配器总结

    1. 非注解方式 1.1 处理器适配器 上一节中使用的处理器适配器是:org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapte ...

  6. java-mybaits-010-mybatis-spring-使用 SqlSession、注入映射器

    一. SqlSession概述 在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession.一旦你获得一个 session 之后,你可以使用它来执行映射语句, ...

  7. 【SpringMVC学习03】SpringMVC中注解和非注解方式下的映射器和适配器总结

    从上一篇的springmvc入门中已经看到,springmvc.xml中的配置了映射器和适配器,是使用非注解的方式来配置的,这是非注解方式的一种,这里再复习一下: 1. 非注解方式 1.1 处理器适配 ...

  8. MyBatis映射器元素

     映射器是MyBatis最强大的工具,也是我们使用MyBatis时用的最多的工具,映射器中主要有增删改查四大元素,来满足不同场景的需要: 下面是主要元素的介绍:         select:查询语句 ...

  9. mybatis映射器配置细则

    前面三篇博客我们已经多次涉及到映射器的使用了,增删查基本上都用过一遍了,但是之前我们只是介绍了基本用法,实际上mybatis中映射器可以配置的地方还是非常多,今天我们就先来看看映射器还有哪些需要配置的 ...

  10. MyBatis中映射器Mapper概述

    MyBatis真正强大之处在于它的映射器.因为它异常强大并且编写相对简单,不仅比传统编写SQL语句做的更好并且能节省将近95%的代码量 XML中顶级元素汇总 cache: 给定命名空间的缓存配置 ca ...

随机推荐

  1. C#商品金额大小写转换

    见图 代码如下 public string NumToChinese(string x) { //数字转换为中文后的数组 string[] P_array_num = new string[] { & ...

  2. centos7_Lnmp编译安装

    17年面试运维岗位的时候,面试官要求输出一份lnmp编译的操作文档,于是有了如下安装nginx+php+mysql,进入正题: 准备环境 环境:centos7.3 软件:nginx-1.12.1 + ...

  3. 【css】 text-align 居中导航

    原理 :利用 inline-block 将 导航 作为 文本 , 被外层具有 text-align 属性的导航盒子包含 .从而实现居中效果 1.  html 结构 <header> < ...

  4. JMS微服务远程调用性能测试 vs .Net Core gRPC服务

    gRPC性能测试(.net 5) 创建一个最简单的gRPC服务,服务器代码如下: using Grpc.Core; using Microsoft.Extensions.Logging; using ...

  5. [转帖]mysql 里 CST 时区的坑

    mysql 里 CST 时区的坑 一.问题简述 mysql 里 CST 时区是个非常坑的概念,因为在 mysql 里CST既表示中国也表示美国的时区.但是在Jdk代码里,CST 这个字符串被理解为Ce ...

  6. [转帖]Linux命令之——rsync

    文章目录 1 rsync是干什么用的 2 rsync和scp有什么区别 3 rsync简单用法介绍 rsync四种工作方式 1. 本地文件系统上实现同步 2. 本地主机使用远程shell和远程主机通信 ...

  7. [转帖]oracle rac后台进程和LMS说明

    本文摘抄录oracle官方文档,oracle rac使用的后台进程,用以备忘,记录之. About Oracle RAC Background Processes The GCS and GES pr ...

  8. [转帖]Kafka之ISR机制的理解

    Kafka对于producer发来的消息怎么保证可靠性? 每个partition都给配上副本,做数据同步,保证数据不丢失. 副本数据同步策略 和zookeeper不同的是,Kafka选择的是全部完成同 ...

  9. Python学习之七_input和print

    Python学习之七_input和print 摘要 python3 之后 函数必须带 () 了 因为我开始学习的比较晚, 所以准备Python3开始学起 前面主要是模仿别人的代码进行学习 后续慢慢学习 ...

  10. 神经网络优化篇:详解超参数调试的实践:Pandas VS Caviar(Hyperparameters tuning in practice: Pandas vs. Caviar)

    超参数调试的实践 如今的深度学习已经应用到许多不同的领域,某个应用领域的超参数设定,有可能通用于另一领域,不同的应用领域出现相互交融.比如,曾经看到过计算机视觉领域中涌现的巧妙方法,比如说Confon ...