mybatis源码探究(-)MapperProxyFactory&MapperProxy
在mybatis中mapperproxyfactory,mapperproxy,mappermethod是三个很重要的类。
弄懂了这3个类你就大概清楚mapper接口与sql的映射,
为什么是接口,没有实例类也可以完成注入或者调用。
其中mappermethod可以参考:mappermethod源码分析传送门
在调用mybatis的addmapper的时候如果你跟踪源码就会最终跟到mapperregistry的addmapper中有如下的语句:
knownmappers.put(type, new mapperproxyfactory<t>(type));
type就是mapper接口。下面我们来看一下mapperproxyfactory的源码。
mapperproxyfactory
public class mapperproxyfactory<t> { private final class<t> mapperinterface; private map<method, mappermethod> methodcache = new concurrenthashmap<method, mappermethod>(); public mapperproxyfactory(class<t> mapperinterface) { this.mapperinterface = mapperinterface; } public class<t> getmapperinterface() { return mapperinterface; } public map<method, mappermethod> getmethodcache() { return methodcache; } @suppresswarnings("unchecked") protected t newinstance(mapperproxy<t> mapperproxy) { return (t) proxy.newproxyinstance(mapperinterface.getclassloader(), new class[] { mapperinterface }, mapperproxy); } public t newinstance(sqlsession sqlsession) { final mapperproxy<t> mapperproxy = new mapperproxy<t>(sqlsession, mapperinterface, methodcache); return newinstance(mapperproxy); } }
mapperproxyfactory一看名字我们就知道肯定是一个工厂类,就是为了生成mapperproxy。其实mapperproxyfactory也非常简单。首先看2个成员mapperinterface就是mapper接口,methodcache就是对mapper接口中的方法和方法的封装类(mappermethod)的映射。mappermethod处理的事情主要就是:处理mapper接口中方法的注解,参数,和返回值。如果想了解更多的细节可以参考mappermethod源码分析传送门
然后就是2个newinstance,看名字就知道是工厂方法,一个是protected,一个是public,所以首先看public方法。发现有一个参数sqlsession,sqlsession处理的其实就是执行一次sql的过程。其实public的newinstance就是new了一个mapperproxy,关于mapperproxy可以先看一下后面的mapperproxy。然后调用了protected的newinstance。
接着我们看protected的newinstance。protected简单明了,就是使用java proxy的工厂方法生成一个了mapper接口的代理类。我想都关系mybatis源码了应该对java的proxy动态代理方式应该非常熟悉了。如果不熟悉可以参考一下我之前写的一篇关于java动态代理的java动态代理细探
我们指定mapperproxy实现了invocationhandler,所以调用mapper接口中的方法走的是mapperproxy的invoke。而mapperproxy的invoke是把method包装成了mappermethod,mappermethod处理了mapper接口方法与xml映射的关系。是不是串联起来了。
mapperproxy
public class mapperproxy<t> implements invocationhandler, serializable { private static final long serialversionuid = -6424540398559729838l; 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; } public object invoke(object proxy, method method, object[] args) throws throwable { if (object.class.equals(method.getdeclaringclass())) { try { return method.invoke(this, args); } catch (throwable t) { throw exceptionutil.unwrapthrowable(t); } } 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; } }
我们看mapperproxy实现了invocationhandler接口,不用仔细想,基本上是因为java动态代理。
既然实现了invocationhandler接口那么当然要先看一下invoke方法了。首先检查了如果是object中方法就直接调用方法本身。
如果不是就把方法method包装成mappermethod,我们前面已经提到了mappermethod主要就是处理方法的注解,参数,返回值,参数与sql语句中的参数的对应关系。再次打一波广告,如果像了解更多mappermethod的细节可以参考mappermethod源码分析传送门
因为把method处理为mappermethod还是一个比较重的操作,所以这里做了缓存处理。
小结
总结一下,我们公共mybatis添加的mapper的操作实际上添加的是mapperproxyfactory,这个是mapperproxy的工厂类,但是mapperproxyfactory生产的也不是mapperproxy,而是mapper的proxy代理。使用的invocationhandler是mapperproxy,mapperproxy的invoke方法实际上是把mapper接口方法包装为了mappermethod,并执行的mappermethod的execute方法。mappermethod处理的逻辑是mapper方法与xml中的sql的一些映射关系。例如@mapkey等注解的处理,一些如rowbounds特殊参数的处理以及一些其他关于mapper方法与sql映射的处理。执行sql的逻辑其实是委托给了sqlsession相关的逻辑。
推荐阅读
-
【MyBatis源码全面解析】MyBatis一二级缓存介绍
-
【MyBatis源码全面解析】MyBatis一二级缓存介绍
-
Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
-
Mybaits 源码解析 (十)----- 全网最详细,没有之一:Spring-Mybatis框架使用与源码解析
-
Mybatis generator生成Service,Controller,添加批量新增数据接口(基于mybatis-generator-1.3.5源码修改)
-
Vue源码探究之状态初始化
-
持久层Mybatis3底层源码分析,原理解析
-
Vue源码探究之虚拟节点的实现
-
连接池-Mybatis源码
-
Mybatis源码解析,一步一步从浅入深(七):执行查询