上篇提到面向接口编程需要使用getMapper获取代理对象,今天我们来看一下mapper代理对象是如何产生的,在此之前先回忆下面试接口编程。
一、Mybatis面向接口编程实践
(一)使用xml的方式
1.定义mapper接口
Mapper接口就是一个普通的接口。
[图片上传失败...(image-f682a9-1542177065563)]
2.定义****mapper映射文件
[图片上传失败...(image-7f393e-1542177065563)]
3.在全局配置文件中配置mapper映射文件
上篇我们也说过,虽有多种方式触发文件解析与接口注入,不做此步骤也能完成(搞清楚一个前提我们现在说的都是在mybatis面向接口编程方式下),但是我们建议通过配置映射文件的方式触发mybatis自动扫描注入。配置方式有多种,不在赘述。我们的配置方式如下:
[图片上传失败...(image-994100-1542177065563)]
4.现在我们测试一下
[图片上传失败...(image-459231-1542177065563)]
测试结果ok。
(二)使用注解的方式。
1.定义mapper接口,同时使用注解
[图片上传失败...(image-70796f-1542177065563)]
2.接口注入。
上篇我们也提到过,虽然用注解不需要xml映射文件,但我们可以通过配置一个只含有namespace的映射文件触发接口注入。如下:
[图片上传失败...(image-cb2a30-1542177065563)]
假如我们就是配置,可以在使用之前调用
sqlsession.getConfiguration().addMapper(IUser.class);
3.测试,假设没有配置xml
[图片上传失败...(image-e96573-1542177065563)]
测试ok.
二、Mybatis面向接口编程之mapper对象的产生
[图片上传失败...(image-d97754-1542177065562)]
[图片上传失败...(image-cbb021-1542177065562)]
[图片上传失败...(image-2ff428-1542177065562)]
mapperRegistry中getMapper,首先通过Class类型在knowMappers中获取mapperProxyFactory.这个变量就是个hashMap,是所有注册的mapper接口,上篇我们提到过。方法直接返mapperProxyFactory.newInstance(sqlSession).我们接着看下
[图片上传失败...(image-201955-1542177065562)]
由此可以看出mybatis直接使用了jdk的动态代理产生了一个mapper接口代理对象。
我 们下面看一下MapperProxy,的invoke方法,MapperProxy是个InvocationHandler
[图片上传失败...(image-40c7b4-1542177065562)]
如果是object中的方法直接调用,比如hashCode,wait.toString..这些,我们接口中并没有default方法。最终会调用最后两行。
接着看下MapperMethod对象的产生
[图片上传失败...(image-d07275-1542177065562)]
他有一个缓存避免了每次都重新生成一个对象,因为这个对象的创建过程比较复杂。
构造方法如下:
[图片上传失败...(image-13faaa-1542177065562)]
SqlCommand和MethodSignature为两个内部类,先看一下SqlCommand
[图片上传失败...(image-e275e2-1542177065562)]
里面如下方法是去全局配置对象查找解析的sql语句生成的类对象,id为接口全类名+方法名,for循环为递归调用,因为接口存在继承关系,方法不一定都声明在本类,也可能在父类,父类的父类。。。。。。。。
[图片上传失败...(image-4abb5b-1542177065562)]
Come on
[图片上传失败...(image-d4fb92-1542177065562)]
通过刚才的satementId取判断Configuration中成员对象mappedStatement中是否包含[图片上传失败...(image-8ae882-1542177065562)]
这个对象便是所有解析的sql语句生成的类对象的map集合,为内部类,继承了hashMap,,重写了put,get方法。key即为namespace+语句id和语句id,两个key对应相同对象,这也是什么用mybatis的时候,语句可以不写namespace的原因。具体解析以后再分析。
判断如果存在对应的sql语句,则取到相应的MappedStatement对象,这个对象包含了映射文件中定义的语句(如select)的所有信息,比如参数,返回值,具体sql,类型(增删盖查)。。。等等等
内部类MethodSignature定义了接口中方法的各种信息。
[图片上传失败...(image-97b844-1542177065562)]
至此MapperMethod对象完成创建。接下来调用execute方法。
[图片上传失败...(image-e84502-1542177065562)]
该方法中根据语句类型,回归原始直接调用了sqlSession中的增删盖查方法,根据配置和方法信息拼装返回结果。到此一个实现了mapper接口的代理对象生成完成,所以你可以尽情的使用此对象调用方法啦。