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至少 ...
随机推荐
- vue之slot用法
slot元素作为组件模板之中的内容分发插槽.这个元素自身将被替换. 有 name 特性的 slot 称为具名 slot. 有 slot 特性的内容将分发到名字相匹配的具名 slot. 一.单个组件 如 ...
- 【C#技术】一篇文章搞掂:Infragistics组件库
工具栏 // 按钮不可按 tool.SharedProps.Enabled = false; Grid // Grid中记录时间 // 建议SQL Server中使用字符字段(没有深入测试,只是字符字 ...
- apache的tomcat负载均衡和集群配置 "
略看了一下,感觉太复杂,要配置的东西太多,因此在这里写出一种更简洁的方法. 要集群tomcat主要是解决SESSION共享的问题,因此我利用memcached来保存session,多台TOMCAT服务 ...
- spring mvc 使用freemark配置
直接在配置中加入 <mvc:annotation-driven/> <!--freemark--> <bean id="freemarkerConfig&quo ...
- Android 将drawable下的图片转换成bitmap、Drawable
将drawable下的图片转换成bitmap . Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xxx ...
- 2019牛客多校第五场B-generator 1(矩阵快速幂)
generator 1 题目传送门 解题思路 矩阵快速幂.只是平时的矩阵快速幂是二进制的,这题要用十进制的快速幂. 代码如下 #include <bits/stdc++.h> #defin ...
- CentOS7 启动docker.service失败
背景:阿里云服务器安装了docker服务,并且更改了仓库位置 需求:让docker正常启动 方法: 一.修改/etc/docker/daemon.json文件后缀 当向该文件中写入仓库配置时,该文件后 ...
- 清除浮动最有效的css写法
说起来呢,基本上只要你给容器div加了float的属性,就需要清除浮动来使页面显示正常,那么,到底有什么方法可以让浮动轻松清除呢? 可以用display:flex;替代,但是它对IE8,9支持不是很好 ...
- 利用HTML和CSS实现常见的布局
水平居中的页面布局中最为常见的一种布局形式,多出现于标题,以及内容区域的组织形式,下面介绍四种实现水平居中的方法(注:下面各个实例中实现的是child元素的对齐操作,child元素的父容器是paren ...
- swapon, swapoff - 使用/关闭用于分页和交换的文件和设备
总览 (SYNOPSIS) /sbin/swapon [-h -V] /sbin/swapon -a [-v] /sbin/swapon [-v] [-p priority] specialfile ...