1.  我们通过接口操作数据库时,发现相关的操作都是在org.apache.ibatis.binding下

  • 从sqSessin 获取getMapper()
SqlSession session = sqlSessionFactory.openSession();
CxCaseMapper caseMapper = session.getMapper(CxCaseMapper.class);
CxCaseTable tablelm = (CxCaseTable) caseMapper.selectById(id);
  • binging 包结构

  可以发现binding 包输入mybatis 下面,是mybatis 的核心文件。这个包中包含有四个类:

  1. BindingException 该包中的异常类
  2. MapperMethod 代理类中真正执行数据库操作的类
  3. MapperProxy 实现了InvocationHandler接口的动态代理类
  4. MapperProxyFactory 为代理工厂
  5. MapperRegistry mybatis中mapper的注册类及对外提供生成代理类接口的类

  在sqlSession初始化的时候,将所有的mapper 注册到了MapperRegistry 中,以Map<Class<?>, MapperProxyFactory<?>>的形式存储。

2. 通过sqlSession接口的代理对象

  • SqSession中持有configuration,configuration中持有mapperRegister、mapperRegister中持有的mapper代理对象工程Map<Class<?>, MapperProxyFactory<?>>。
  • 当mapperRegister通过getMapper方法获取,代理对象的时候,流程已经进入到binding 包中。
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//以mapper的class对象为key值,获取当面mapper的代理对象工厂
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
//如果没有获取到代理对象工厂 抛出BindingException 异常信息
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
//用获取到的代理对象工厂,生产目标对象以及目标代理对象
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
  • 代理对象工厂生产目标对象已经目标代理对象
  @SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
// 3.mapperProxy实现了InvocationHandler接口,主要为具体接口的代理
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
} public T newInstance(SqlSession sqlSession) {
// 1. 产生目标对象MapperProxy
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
// 2. 根据目标对象,产生代理对象
return newInstance(mapperProxy);
}

 3.mapperProxy

  • 这个类继承了InvocationHandler接口,我们主要看这个类中的两个方法。一是生成具体代理类的函数newMapperProxy,另一个就是实现InvocationHandler接口的invoke。我们先看invoke方法。
public class MapperProxy<T> implements InvocationHandler, Serializable {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//并不是任何一个方法都需要执行调用代理对象进行执行,如果这个方法是Object中通用的方法(toString、hashCode等)无需执行
if (Object.class.equals(method.getDeclaringClass())) {
try {
return method.invoke(this, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
//生成MapperMethod对象,从cache中获取
final MapperMethod mapperMethod = cachedMapperMethod(method);
//执行MapperMethod对象的execute方法,目标方法的执行
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;
} }

4. mapperMethod

  • 在初始化后就是向外提供的函数了,这个类向外提供服务主要是通过如下的函数进行:
public class MapperMethod {
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
//根据初始化时确定的命令类型,选择对应的操作
if (SqlCommandType.INSERT == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
} else if (SqlCommandType.UPDATE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
} else if (SqlCommandType.DELETE == command.getType()) {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
} else if (SqlCommandType.SELECT == command.getType()) {
//相比较而言,查询稍微有些复杂,不同的返回结果类型有不同的处理方法
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
//这个函数整体上还是调用sqlSession的各个函数进行相应的操作,在执行的过程中用到了初始化时的各个参数。
result = sqlSession.selectOne(command.getName(), param);
}
} else if (SqlCommandType.FLUSH == command.getType()) {
result = sqlSession.flushStatements();
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
}

5 总结:

mybatis源码分析(4)----org.apache.ibatis.binding包的更多相关文章

  1. MyBatis源码分析(5)——内置DataSource实现

    @(MyBatis)[DataSource] MyBatis源码分析(5)--内置DataSource实现 MyBatis内置了两个DataSource的实现:UnpooledDataSource,该 ...

  2. MyBatis源码分析(4)—— Cache构建以及应用

    @(MyBatis)[Cache] MyBatis源码分析--Cache构建以及应用 SqlSession使用缓存流程 如果开启了二级缓存,而Executor会使用CachingExecutor来装饰 ...

  3. Mybatis源码分析-BaseExecutor

    根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...

  4. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  5. Mybatis源码分析之Cache二级缓存原理 (五)

    一:Cache类的介绍 讲解缓存之前我们需要先了解一下Cache接口以及实现MyBatis定义了一个org.apache.ibatis.cache.Cache接口作为其Cache提供者的SPI(Ser ...

  6. MyBatis 源码分析

    MyBatis 运行过程 传统的 JDBC 编程查询数据库的代码和过程总结. 加载驱动. 创建连接,Connection 对象. 根据 Connection 创建 Statement 或者 Prepa ...

  7. (一) Mybatis源码分析-解析器模块

    Mybatis源码分析-解析器模块 原创-转载请说明出处 1. 解析器模块的作用 对XPath进行封装,为mybatis-config.xml配置文件以及映射文件提供支持 为处理动态 SQL 语句中的 ...

  8. 精尽 MyBatis 源码分析 - 基础支持层

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  9. 精尽 MyBatis 源码分析 - MyBatis 初始化(一)之加载 mybatis-config.xml

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  10. 精尽MyBatis源码分析 - MyBatis初始化(二)之加载Mapper接口与XML映射文件

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

随机推荐

  1. 使用navicat for sqlserver 把excel中的数据导入到sqlserver数据库

    以前记得使用excel向mysql中导入过数据,今天使用excel向sqlserver2005导入了数据,在此把做法记录一下 第一步:准备excel数据,在这个excel中有3个sheet,每个she ...

  2. python代码这样写会更优雅

    1.链式比较操作 age = 18 if age > 18 and age < 60: print("young man") pythonic if 18 < a ...

  3. Guava cache功能简介(转)

    原文链接:http://ifeve.com/google-guava-cachesexplained/ 范例 LoadingCache<Key, Graph> graphs = Cache ...

  4. PHP--- JSON和数组的转换

    一.json_encode() <?php $arr =array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); echo json_ ...

  5. 移动端touch滑屏事件

    <script> var windowHeight = $(window).height(), $body = $("body");// console.log($(w ...

  6. POJ 3186Treats for the Cows(区间DP)

    题目链接:http://poj.org/problem?id=3186 题目大意:给出的一系列的数字,可以看成一个双向队列,每次只能从队首或者队尾出队,第n个出队就拿这个数乘以n,最后将和加起来,求最 ...

  7. Linux 基础——文件搜索命令find

    一.find命令的好处 有时会经常在目录下找文件或目录的具体存放在哪,但是该目录下的文件又很多不好找出.这时并不需要手动查看所有的文件,用find命令来帮助查找就行了.所以文件或目录一定归好类,存放有 ...

  8. python进行des加密解密,而且可以与JAVA进行互相加密解密

    import binasciifrom pyDes import des, CBC, PAD_PKCS5import uuidimport time # pip install -i https:// ...

  9. Bzoj2152/洛谷P2634 聪聪可可(点分治)

    题面 Bzoj 洛谷 题解 点分治套路走一波,考虑\(calc\)函数怎么写,存一下每条路径在\(\%3\)意义下的路径总数,假设为\(tot[i]\)即\(\equiv i(mod\ 3)\),这时 ...

  10. cogs——2478. [HZOI 2016]简单的最近公共祖先

    2478. [HZOI 2016]简单的最近公共祖先 ★☆   输入文件:easy_LCA.in   输出文件:easy_LCA.out   简单对比时间限制:2 s   内存限制:128 MB [题 ...