为啥Mybatis接口不需要实现类就可以和xml文件建立练习

在使用mybatis框架时,我们发现mapper接口是没有实现类的,取而代之的是一个xml文件。也就是说我们调用mapper接口,实际上是使用了对应的mapper.xml中定义sql语句完成数据操作的。

那么我们有没有想过,为什么mapper接口没有实现类,它是如何和xml关联起来的?

我们在学习java 基础时,知道接口是不可以直接调用的,只有通过定义实现类了实现接口,然后new一个实现类对象,再将实现类对象赋给接口声明的对象。调用接口的方法实际上就是调用被引用对象的方法,也就是实现类实现的方法。那么为啥Mybatis的接口不需要实现类呢?

下面我们就以查询所有员工数据为例,进行一步一步的调试,查看底层是怎么操作的呢?

EmployeeMapper接口

EmployeeMapper.xml文件的sql语句

那么getAllEmp方法被调用的时候,被引用的对象是谁呢?接口被调用时候发生了什么?

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

在学习代理模式时,有一个动态代理模式,通过动态代理接口的所有方法,每次接口被调用,就会进入动态代理对象的invoke方法,然后加载xml中的sql完成操作数据库,再返回结果。

那么Mybatis 的Mapper接口有没有可能被动态代理对象来实现,完成后面的操作呢?

接下来我们进入debug模式来调试看看。

(1)在sqlSession.getMapper(EmployeeMapper.class)这里设置一个断点

(2)继续走到Configuration类的getMapper方法里,Configuration主要存储 Mybatis 所有的配置信息,包括mybatis配置文件、EmployeeMapper.xml等文件都会被预先加载到Configuration里。

这时候,我们发现Configuration里面出现了一个mapperRegistry,这个是mapper的注册器,其实在加载EmployeeMapper.xml的时候,我们就需要在mapperRegistry里面进行注册,所以,我们可以从这里进行获取。继续走~

(3)进入到mapperRegistry的getMapper方法

这里分为了两步执行:

(1)knownMappers.get(type);

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

(2)mapperProxyFactory.newInstance(sqlSession);

代理工厂生成动态代理返回

那么knownMappers其实是个map集合,根据EmployeeMapper.class获取MapperProxyFactory,所以knownMappers必然是源码前面的步骤中set进去的。我们先找找,到底是哪里set进去的呢,继续调试我们发现XMLMapperBuilder类的bindMapperForNamespace方法

这个方法里面的boundType,是通过Resources.classForName(namespace);生成的class,Resources.classForName底层其实就是调用Class.forName生成的反射对象,而参数是namespace,

namespace就是com.mybatis3.mappers.EmployeeMapper:

Class.forName(com.mybatis3.mappers.EmployeeMapper)生成反射对象。生成的boundType在被configuration.addMapper(boundType);可以看到在这里调用了put方法放进去的。

(4)接下来再回到mapperRegistry的getMapper方法继续往下调试进入到MapperProxyFactory的newInstance里面,看到该方法return newInstance(mapperProxy)回来,继续往下调试

(5)进入到newInstance这个方法里面我们看到了Proxy.newProxyInstance代码,就是JDK创建代理的方法

到这里我们发现是调用了JDK动态代理的newProxyInstance方法。

(6)那么我们来看看是如何代理的,打开MapperProxy这个类,找到里面的invoke方法

在这个方法里面MapperMethod 类有两个重点,其一就是初始化,其二就是执行SQL,为什么说初始化很重要呢?因为初始化的时候需要通过接口名全称+方法全称去 Configuration 找我们之前加载的SQL,这也就是为什么接口方法定义和SQL的ID必须保持一致的原因;其二执行SQL。

(7)接着MapperMethod 调用 execute 执行 SQL,代码很简单如下

在Case:SELECT下 我们找到

result = this.executeForMany(sqlSession, args);

(8)我们点开executeForMany方法

最终我们发现是调用了sqlSession.selectList方法,然后根据方法名找到EmployeeMapper.xml文件中对应id标识,执行sql语句完成了查询操作。

总结

今天我们从认为Mapper接口是创建出来的代理对象完成了查询操作出发,一步步进行了调试发现,最终Mybatis的接口不需要实现类,实际上是使用了JDK动态代理的方式创建代理对象完成的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值