北京看白癜风去哪家医院最好 http://www.wzqsyl.com/m/在使用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就是