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源码探究(-)MapperProxyFactory&MapperProxy的更多相关文章
- Mybatis日志源码探究
一.项目搭建 1.pom.xml <dependencies> <dependency> <groupId>log4j</groupId> <ar ...
- Spring Framework自动装配setAutowireMode和Mybatis案例的源码探究
由前文可得知, Spring Framework的自动装配有两种方式:xml配置和注解配置: 自动装配的类型有: (1)xml配置中的byType根据类型查找(@Autowired注解是默认根据类型查 ...
- Mybatis源码解析 - mapper代理对象的生成,你有想过吗
前言 开心一刻 本人幼教老师,冬天戴帽子进教室,被小朋友看到,这时候,有个小家伙对我说:老师你的帽子太丑,赶紧摘了吧.我逗他:那你好好学习,以后给老师买个漂亮的?这孩子想都没想立刻回答:等我赚钱了,带 ...
- MyBatis源码解读(3)——MapperMethod
在前面两篇的MyBatis源码解读中,我们一路跟踪到了MapperProxy,知道了尽管是使用了动态代理技术使得我们能直接使用接口方法.为巩固加深动态代理,我们不妨再来回忆一遍何为动态代理. 我相信在 ...
- Mybatis源码解析-MapperRegistry注册mapper接口
知识储备 SqlsessionFactory-mybatis持久层操作数据的根本,具体的解析是通过SqlSessionFactoryBean生成的,具体的形成可见>>>Spring ...
- Mybatis源码解析-MapperRegistry代理注册mapper接口
知识储备 SqlsessionFactory-mybatis持久层操作数据的前提,具体的解析是通过SqlSessionFactoryBean生成的,可见>>>Spring mybat ...
- 【转】Mybatis源码解读-设计模式总结
原文:http://www.crazyant.net/2022.html?jqbmtw=b90da1&gsjulo=kpzaa1 虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开 ...
- MyBatis 源码分析 - SQL 的执行过程
* 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...
- Mybatis源码解读-设计模式总结
虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...
随机推荐
- 用orm操作sql数据库的优缺点
一,sql注入问题 二,代码和sql写死在了一起,导致解耦差 三,sql开发人员水平不一,导致sql性能问题 四,开发效率差 使用orm的优点: 一,实现了代码与sql数据的解耦合 二,不需要写原生s ...
- Android的Context && 安卓常用系统服务(当前运行包名/当前网络状态和开关网络/音频服务/马达服务) (转)
转:http://blog.csdn.net/zhandoushi1982/article/details/8501773 Context字面意思上下文,位于framework 的android.co ...
- php开发面试题---Apache 运行PHP原理(整理)
php开发面试题---Apache 运行PHP原理(整理) 一.总结 一句话总结: 不要忘记 php引擎将页面静态化 和 php引擎和apache之间通讯 反思的回顾非常有用,因为决定了我的方向和技巧 ...
- 46、tensorflow入门初步,手写识别0,1,2,3,4,5,6
1.使用tensorflow的SoftMax函数,对手写数字进行识别 Administrator@SuperComputer MINGW64 ~ $ docker run -it -p 8888:88 ...
- vim 更改注释颜色
在 ~/.vimrc 添加命令: highlight Comment ctermfg=green
- 查看mysql慢日志,进行优化
MySQL 慢查询的相关参数解释:slow_query_log :是否开启慢查询日志,1表示开启,0表示关闭. slow_query_log :是否开启慢查询日志,1表示开启,0表示关闭. lo ...
- linux shell unzip multiple zip files
find . -name "*.result.zip" | xargs -n 1 unzip - -P password -d ../ext_logs
- Node.js、vue.js的使用
Vue.js的使用 1.下载Node.js 2.打开cmd 3.执行命令 npm i 4.输入命令 npm run serve 5.浏览器打开 http://localhost:8080
- spark textFile读取多个文件
1.spark textFile读取File 1.1 简单读取文件 val spark = SparkSession.builder() .appName("demo") .mas ...
- 记录一下取ul中li的值
//#id 事件 $('#onLineUser').on('click','li',function () { $(".list-group-item").removeClass( ...