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. MySQL源码分析(一)

    近段时间简单看了下Mysql源码相关内容,主要从一个select查询出发,查看了一下整个代码结构.分析总结如下: https://mubu.com/doc/explore/13965

  2. S3C6410 SPI全双工读写流程分析(原创)【转】

    转自:http://blog.csdn.net/hustyangju/article/details/21165721 原创博文,知识共享!转载请注明出处:http://blog.csdn.net/h ...

  3. julia 1.0如何使用pkg

    输入]进入pkg模式 add 加包名即可安装,如 add Cxx

  4. learnyounode 题解

    //第三题 var fs =require('fs')var path=process.argv[2]fs.readFile(path,function(err,data){ var lines=da ...

  5. Linux下web服务的搭建

    1.安装Apache Apache的官网地址为:http://httpd.apache.org/,这里以源码的方式进行安装,我们下载的版本是“httpd-2.4.25.tar.gz”,下载后的压缩文件 ...

  6. Windows内核分析——内核调试机制的实现(NtCreateDebugObject、DbgkpPostFakeProcessCreateMessages、DbgkpPostFakeThreadMessages分析)

    本文主要分析内核中与调试相关的几个内核函数. 首先是NtCreateDebugObject函数,用于创建一个内核调试对象,分析程序可知,其实只是一层对ObCreateObject的封装,并初始化一些结 ...

  7. WordPress 用户管理插件 WP User Manager

    WP User Manager 是一个较新的用户管理插件,可以在前端实现 用户注册.登录.找回密码.修改个人资料.修改密码等功能,如果你在找这方面的插件,WP User Manager 应该是一个不错 ...

  8. Hadoop(七)YARN的资源调度

    一.YARN 概述 YARN 是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操 作系统平台,而 MapReduce 等运算程序则相当于运行于操作系统之上的应用程序 YARN ...

  9. Model Binder

    上面需检测id是否为null 如果未提供id值或id值类型不匹配,则使用默认值.但仍需校验值是否超出范围    

  10. github 笔记(一)

    笔记预留 0. echo "# Try" >> README.md git init git add README.md git commit -m "fir ...