Mybatis 源码分析:获取 Mapper 接口对象

Mybatis接口Mapper内的方法为啥不能重载?Mapper源码分析 精髓:动态代理的功能:通过拦截器方法回调,对目标target方法进行增强。 言外之意就是为了增强目标target方法。上面这句话没错,但也不要认为它就是真理,殊不知,动态代理还有投鞭断流的霸权,连目标target都不要的科幻模式。 注:本文默认认为,读者对动态代理的原理是理解的,如果不明白target的含义,难以看懂本篇文章,建议先理解动态代理。 本文分享给需要面试刷题的朋友,也祝愿大家顺利拿到自己想要的offer,这份资料主要包含了Java基础,数据结构,jvm,多线程等等,由于篇幅有限,以下只展示小部分 阅读详情

我们知道使用 mybatis 作为 ORM 框架时,想要使用面向接口的方式操作数据库,即使用 mapper 文件形式,那么就需要获取 Mapper 接口对象,从而才能对数据库进行操作。那么问题来了,在 java 中是不可能对 interface 进行 new 的,那么 mybatis 是怎么做到面向 Mapper 接口的呢?那就从源码的角度揭开这层其实没有想象那么高深的面纱!
首先来看看 SqlSession(默认实现 DefaultSqlSession) 类的 getMapper() 方法。

@Override
public <T> T getMapper(Class<T> type) {
	return configuration.<T>getMapper(type, this);
}

非常简单,它把获取 mapper 接口的对象逻辑委托给了 Configuration 类的 getMapper() 方法。

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
}

这看起来似乎有那么点意思了,它从 mapperRegistry 中去获取 mapper 接口对象,并且还把 SqlSession 传递过去。看过我之前的文章应该清楚 mapperRegistry 是什么东西,从字面意思来看,它就是 Mapper 注册中心,它的定义是:

protected final MapperRegistry mapperRegistry = new MapperRegistry(this);

那么接下来应该是到了揭开面纱的门口了,我们看看 MapperRegistry 类的 getMapper() 方法又干了啥呢?

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
}

可以看到,首先会从 knownMappers 获取 Mapper 接口对应的 MapperProxyFactory 对象,那 knownMappers 又是什么呢,在之前的文章有说到,它就是在构建 SqlSessionFactory 对象时,对 xml 配置文件解析后把所有的 mapper 接口都会放入在 knownMappers 这个 HashMap 中去,key 为 mapper 接口的全限定名,value 为 MapperProxyFactory 对象。knownMappers 字段的定义为:

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

然后,会使用 MapperProxyFactory 类的 newInstance() 方法,此时就是揭开面纱见证奇迹的时刻到了,看看这个方法到底干了啥

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

这里首先生成了一个 MapperProxy 对象,那这个对象又是啥呢,字面意思看起来是 Mapper 的代理对象,这个稍等说。方法之后又掉用了一个重载的 newInstance() 方法:

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

千呼万唤始出来,终于见到了最核心的一行代码,它使用了 jdk 自带的动态代理机制对 Mapper 接口生成了一个代理对象,在这里可以看到 MapperProxy 是作为 Proxy.newProxyInstance() 方法的第三个参数传递进去的,所以可以想象到 MapperProxy 肯定实现了 jdk 的 InvocationHandler 接口。

public class MapperProxy<T> implements InvocationHandler, Serializable {
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

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

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  	// ...
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }
}

现在,我们就知道了获取 Mapper 接口对象的整个流程,至于之后对其进行方法调用的过程,且看下回分解~~~
最后,老规矩附上整个过程的时序图:
获取 mapper 接口对象

mybatis系列之mapper接口 每天早上七点三十,准时推送干货hello~各位读者好,我是鸭血粉丝(大家可以称呼我为「阿粉」)。今天,阿粉带着大家来了解一下 mybatis 接口的创建。1.上期回顾首先,我们还是回顾一... 阅读详情

相关推荐

海康VisionMaster与西门子Smart 200进行S7通信

海康VisionMaster与西门子Smart 200进行S7通信

haier123888的博客 8070

Mybatis 获取Mapper对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(this.getClass().getClassLoader().getResourceAsStream("mybatis-config.xml")); SqlSession sqlSession = sqlSessionFactory.openSession(); User userMapper = sqlSession.getMapper(Use

weixin_44730681的博客 2704

深度学习部署工程师--8(docker+TensorRT部署到推理+yolo人体检测)下

本文介绍了YOLOv5模型通过TensorRT加速部署的流程。首先需要检查磁盘空间,确保有30GB可用。文章对比了不同推理方式的性能:int8量化+TensorRT可达200FPS,纯TensorRT为166FPS,CUDA为147FPS,CPU为93FPS。重点讲解了将YOLOv5模型导出为ONNX格式的详细步骤,包括修改Detect类的forward方法以移除decode运算,使用git patch批量修改代码,安装必要的依赖库,以及通过onnx-graphsurgeon工具修改ONNX图结构。最终目标

FJN110的博客 464

MyBatis 源码解读-获得Mapper 对象

现在我们已经有一个DefaultSqlSession 了,必须找到Mapper.xml 里面定义的Statement ID,才能执行对应的SQL 语句。 找到Statement ID 有两种方式:一种是直接调用session 的方法,在参数里面传入Statement ID,这种方式属于硬编码,我们没办法知道有多少处调用,修改起来也很麻烦。 另一个问题是如果参数传入错误,在编译阶段也是不会报错的,不利于预先发现问题。 Blog blog = (Blog) session.selectOne("com.

Leon_Jinhai_Sun的博客 385

mapper新增数据传入参数为实体对象,如何获取该实体的主键ID

tk.mapper 新增一条数据之后,要想获得该信息的 id , 只需要在新增完数据之后,获取一下该实体类的 id。

weixin_44491927的博客 2878

MyBatis-获取 xxxMapper(源码)

Main 方法,mybatis 版本为 3.5.0 使用 MapperProxyFactory 创建一个 MapperProxy 的代理对象 代理对象里面包含了 DefaultSqlSession(Executor) InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSes...

weixin_30251829的博客 171

MyBatis原理分析之获取Mapper接口的代理对象

前置博文: MyBatis原理分析之获取SqlSessionFactory MyBatis原理分析之获取SqlSession 本篇博文是原理分析的第三篇。 当使用mapper接口进行CRUD时,其实是其代理对象在发挥作用,SQLsession获取mapper接口MapperProxy的代理对象时序图如下: 【1】DefaultSqlSession 如下代码所示,这里其实是调用了configuration实例的方法。该方法是一个泛型方法,参数有Class<T> type表示你的接口Class对

小小默:进无止境 3518

Mybatis(六):源码分析-获取Mapper接口动态代理对象

从官网Demo代码来入手:https://mybatis.org/mybatis-3/zh/getting-started.html 根据Mapper.Class对象获取接口的代理对象(映射器) // 从 SqlSessionFactory 中获取 SqlSession try (SqlSession session = sqlSessionFactory.openSession()) { // 映射代理器,根据Mapper.Class对象获取接口的代理对象 BlogMapper mapp

weixin_40074110的博客 1146

解析 MyBatisMapper 生效的前因后果

J3 - 白起 技术(MyBatis # Mapper分析) 最近闲了快有半个多月了,一直提不起兴致再去看一些书籍(没有以前疯狂吸食知识的欲望了????)。 不过这一两天不知道是什么筋搭错了非常想写点什么,但又不知道写点啥(苦恼)。所以我就结合了一下本人工作中经常用到但没有深入的技术下手了,最后思来想去就选择了 MyBatisMapper 文件这一块的知识内容入手了。 以前只是知道写一个 Mapper 接口,对应着再去写一个 Mapper.xml 文件然后将 Mapper 接口位置和 Mapper

技术分享、唠嗑水文、如有不周、还望海涵 727

源码分析-Spring是如何与Mybatis整合的?

本文主要讲Spring和Mybatis整合的源码分析,侧重点在于源码分析Spring如何将我们定义的Mapper接口加载到Spring容器内?我们从Spring容器获取到的Mapper对象到底是什么?它又是如何来的?Mybatis部分的相关源码不会着重讲。 这部分源码主要在mybatis-spring这个jar包中,此jar包不是Spring官方的,看Spring的做法,可能Spring项目组没太看的上mybatis这个ORM框架,毕竟mybatis属于半自动框架,国外程序员可能更偏向于JPA这种。不过,目

佛系程序员 302

Mybatis-接口代理方式Dao

传统的方式实现Dao层,我们既要写接口,还要写实现类。而MyBatis框架可以帮我们省略编写Dao层接口实现类的步骤。程序员只要编写接口就行了,Mybatis框架自身可以根据接口的定义来创建接口的动态代理对象。(1) Mapper.xml文件中的namespace与mapper接口的全限定名(全类名)相同。 (2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同。 (3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameter..

金鳞踏雨 904

mybatis源码分析(四)---------------代理对象的生成

mybatis两种开发方式这边文章中,我们提到了Mapper动态代理开发这种方式,现在抛出一个问题:通过sqlSession.getMapper(XXXMapper.class)来获取代理对象的过程是怎样的?生成的代理对象是通过怎样的方式来调用Mapper接口指定的方法的? 我们根据源码来一步步分析: 首先进入getMapper方法,通过一步步追踪,我们可以进入到MapperRegistry...

weixin_30483013的博客 89

JAVA—— Mybatis高级(进阶)

文章目录一.接口代理方式实现Dao1.1 代理开发方式介绍1.2.编写StudentMapper接口1.3 测试代理方式1.4 源码分析1.5 知识小结二. 动态sql语句2.1 动态sql语句概述2.2 动态 SQL 之<**if>**2.3 动态 SQL 之<**foreach>**2.4 SQL片段抽取2.5 知识小结三. 分页插件3.1 分页插件介绍3.2 分页插件的使用3.3 分页插件的参数获取3.4 分页插件知识小结四.MyBatis的多表操作4.1 多表模型介

weixin_50594210的博客 812

接口调用什么意思_美团面试:为什么就能直接调用userMapper接口的方法?

字数:2434,阅读耗时:3分40秒。老规矩,先上案例代码,这样大家可以更加熟悉是如何使用的,看过Mybatis系列的小伙伴,对这段代码差不多都可以背下来了。哈哈~,有点夸张吗?不夸张的,就这行代码。 public class MybatisApplication { public static final String URL = "jdbc:mysql://localho...

weixin_39861255的博客 396

mysql创建临时表写在mybatis_快速上手第一个MyBatis程序

1.1、环境准备1、搭建实验数据库-- 创建数据库CREATE DATABASE `mybatis`;-- 使用数据库USE `mybatis`;-- 创建用户表CREATE TABLE `user`( `id` INT(15) NOT NULL PRIMARY KEY AUTO_INCREMENT, `username` VARCHAR(16) NOT NULL COMMENT '...

weixin_39612110的博客 536

美团面试:为什么就能直接调用userMapper接口的方法?

关注“Java后端技术全栈”回复“面试”获取全套面试资料字数:2434,阅读耗时:3分40秒。老规矩,先上案例代码,这样大家可以更加熟悉是如何使用的,看过Mybatis系列的小伙伴,对这...

田维常 712

BeanFactory和FactoryBean的区别

1. 前言 在getBean方法中,即 bean 实例化完成之后,存在这样一段代码: 从方法名上可以得知它是用来通过实例创建对象的,既然上面已经创建了,这里为什么还会在创建一次呢?这就和FactoryBean有关。 2. BeanFactory和FactoryBean 从定义上看,一个是bean工厂,一个是工厂bean,在 Spring 中,它们都是一个接口,都可以用来创建Bean实例,但各自的功能点却又存在不同。 2.1 BeanFactory BeanFactory,他是Spring容器的一个顶层接口

个人站点:javatv.net 1882

mybatis的原理详解

默认情况下它会关闭连接。POOLED- 这种数源的实现利用"池"的概念将JDBC连接对象组织起来,避免了创建新建的连接实列时所必须的初始化和认证时间。JNDI - 这个数据源实现是为了能在入EJB 或者应用服务器这类容器中使用的,容器可以集中或外部配置数据源,然而放置一个JNDI上下文的数据源引用。第一种采用JDBC事务类型,直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。environment标签中的id属性必须和enviroments标签中的default属性一致。

m0_56245143的博客 742

mybatismapper为啥只有接口没有实现类,它却能工作?

这时候,我们发现Configuration里面出现了一个mapperRegistry,翻译过来可以理解为mapper的注册器,其实在加载UserMapper.xml的时候,我们就需要在mapperRegistry里面进行注册,所有,我们可以从这里面进行获取。那么只能是动态代理,动态代理接口的所有方法,每次接口被调用,就会进入动态代理对象的invoke方法,然后加载xml中的sql完成操作数据库,再返回结果。所以,动态代理代理还是对象类,那么我们只有接口,不能new,哪来的对象呢?,就是反射生成的这个对象

LoveSummer 1万+

MyBatis源码分析——调用Mapper接口方法执行SQL

文章目录MyBatis源码分析调用Mapper接口方法执行SQL整体操作流程相关参考 MyBatis源码分析 调用Mapper接口方法执行SQL 在第二组测试代码中,通过SqlSession.getMapper()方法获取自定义Mapper接口,并通过执行Mapper接口的方法完成sql查询,由于Mapper接口,并没有实现类,那么它是如何完成方法执行呢?并切在与spring整合的时候又是为何M...

SK_Jaco的博客 3023

网络扫描仪 Fing v9.2.1.apk

Fing是一款功能十分强大的网络扫描仪,拥有十多种免费网络工具,包括:Wi-Fi 扫描程序、端口扫描程序、DNS 查找、ping 和服务监控,可以更快的了解网络是否安全

上一篇: Mybatis 源码分析:Mapper 解析过程
下一篇: UML 类之间关系总结
迷茫的老人
博客等级 码龄15年 21粉丝 26原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值