写点什么

为啥 mybatis 的 mapper 只有接口没有实现类,但它却能工作?(全网独一份!

用户头像
Android架构
关注
发布于: 14 小时前


说起 mybatis,大伙应该都用过,有些人甚至底层源码都看过了。在 mybatis 中,mapper 接口是没有实现类的,取而代之的是一个 xml 文件。也就是说我们调用 mapper 接口,其实是使用了 mapper.xml 中定义 sql 完成数据操作。


大家有没想过,为什么 mapper 没有实现类,它是如何和 xml 关联起来的?


一个简单的例子


ok,别急,现在我们已经抛出问题,现在我们从 demo 开始,再结合我们所拥有的知识点出发,一一剖析整个过程。


先来搞个简单的查询:


UserMapper 一个接口:



userMapper.xml 的 sql 语句



猜想


我们知道,接口是不直接被初始化的,但是可以被实现,所以 new 对象的时候是初始化实现类,然后接口再引用该对象。那么调用接口的方法实际上就是调用被引用对象的方法,也就是实现类的方法。


那么,UserMapper.findById 被调用时候,不禁有这两个疑问?


  • 被引用的对象是谁呢?

  • 接口被调用时候发生了什么?


我们先来回答第二个问题,既然找不到实现类,UserMapper 有没可能被代理起来呢,findById 方法调用时候,我们找到代理对象来执行就行了。


代理有两种方式:


  • 静态代理

  • 动态代理


而静态代理基本是不可能的了,静态代理需要对 UserMapper 所有的方法进行重写。那么只能是动态代理,动态代理接口的所有方法,每次接口被调用,就会进入动态代理对象的 invoke 方法,然后加载 xml 中的 sql 完成操作数据库,再返回结果。


再然后说到动态代理,常见的方式有以下 2 种方式:


JDK 动态代理:


  • 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理。

  • CGlib 动态代理:

  • 利用 ASM(开源的 Java 字节码编辑库,操作字节码)开源包,将代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理。


所以,动态代理代理还是对象类,那么我们只有接口,不能 new,哪来的对象呢?别忘了,我们还有反射机制,我们是不是可以通过反射给接口生成对象,还记得**Class.**forName 吗。


综合上面的猜想:


第一步:通过反射机制给接口生成对象


第二步:动态代理反射对象,这样接口被调用,就会触发动态代理


嗯,好像有点道理,我果然是个天才!


知识点:动态代理


动态代理有几种实现方式,这里我们就先讲 JDK 动态代理,使用步骤如下:


  • 新建一个接口

  • 创建代理类,实现 java.lang.reflect.InvocationHandler 接口

  • 接口测试


接口我们就用 UserMapper,我们来写个代理对象。





ok,一个简单的动态代理例子送给你们,上面代码中关键生成动态代理对象的关键代码是:



  • loader: 用哪个类加载器去加载代理对象

  • interfaces:动态代理类需要实现的接口

  • h:动态代理方法在执行时,会调用 h 里面的 invoke 方法去执行


源码分析


好啦,上面该做的准备已经都准备好了,我们对 mybatis 的这个 mapper 接口大概都有些思路了,下面我们去正式验证一下,那么肯定就要去看源码了。我们只是去验证上面的 mapper 接口问题,所以不需要去看全部的代码,当然如果你看整个流程下来的话,会更加清晰。


论证猜想,我们可以采用结果导向的方式去看源码,从获取 mapper 那里开始看,也就是



主要从 sqlSession.getMapper(UserMapper.class);这里开始,先看整个 UserMapper 是不是被动态代理的。ok,我们进入代码中:


  • org.apache.ibatis.session.SqlSessionManager#getMapper



继续走到 Configuration 方法里,Configuration 是 mybatis 所有配置相关的地方,mybatis-cfg.xml、UserMapper.xml 等文件都会被预先加载到 Configuration 里。


  • org.apache.ibatis.session.Configuration#getMapper



这时候,我们发现 Configuration 里面出现了一个 mapperRegistry,翻译过来可以理解为 mapper 的注册器,其实在加载 User


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


Mapper.xml 的时候,我们就需要在 mapperRegistry 里面进行注册,所有,我们可以从这里面进行获取。继续走~


  • org.apache.ibatis.binding.MapperRegistry#getMapper



ok,这里分为了两步:


  • knownMappers.get(type);

  • 获取已知的加载过的 mapper 中获取出 mapper 代理工厂

  • mapperProxyFactory.newInstance(sqlSession);

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
为啥mybatis的mapper只有接口没有实现类,但它却能工作?(全网独一份!