mybatis mybatis-spring 源码流程分析

前言

实际项目中通常使用mybatis-spring获得mapper的bean对象。本文通过 mybatis 和 mybatis-spring 的源码流程 了解其实现方式。

mybatis-logo

mybatis doc

http://www.mybatis.org/mybatis-3/zh/getting-started.html

mybatis-spring doc

http://www.mybatis.org/spring/zh/index.html

mybatis-spring github

https://github.com/mybatis/spring


mybatis 源码流程

session & binding

SqlSession session = sqlSessionFactory.openSession();
try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
} finally {
  session.close();
}

第一部分:构造sessionFactory

第二部分 查询

    1. sqlsession.getMapper() 返回的是接口的 动态代理 MapperProxy
    1. 接口调用时 MapperProxy.invoke()调用,根据方法名获取MapperMethod
    1. 执行MapperMethod.execute() 根据mapper标签区分CRUD操作,调用sqlSession。

transaction

    1. Transaction接口 包装了connection, 管理其声明周期,创建,提交,回滚,关闭。
    1. 有两种实现, JDBC事务 和 Managed交由spring处理。

datasource

    1. POOLED 带连接池的 数据源
      PooledDataSource.getconnection() 调用popConnection()从空闲连接中获取PooledConnection对象。
      如果idleConnections非空,直接取其中的一个返回。
      如果activeConnections 活跃连接数小于 配置的上限,则创建一个新的连接返回。
      如果无可用连接,等待后再次获取。
      最后 获取将准备返回的conn记录到activeConnections中。

PooledConnection是Connection的一个动态代理。主要为了在调用connection对象的接口前,检查连接是否过期。另外,如果调用close,会将connect归还连接池。

    1. UNPOOLED 不带连接池 的数据源
      UnpooledDataSource.getconnection() 使用JDBC API 从 DriverManager获取连接。
      PooledDataSource也是通过UnpooledDataSource获取底层的连接。

plugin

// ExamplePlugin.java
@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  public Object intercept(Invocation invocation) throws Throwable {
    return invocation.proceed();
  }
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  public void setProperties(Properties properties) {
  }
}
    1. 实现Interceptor 接口,并通过Intercepts注解 指明需要拦截的方法。可以拦截 Executor ,ParameterHandler ,ResultSetHandler ,StatementHandler 的方法。
    1. 解析配置文件时,解析plugin标签,生成一个拦截器的列表 InterceptorChain对象。
    1. 通过Configuration工厂方法 newExecutor newStatementHandler newParameterHandler newResultSetHandler 中会 通过 interceptorChain.pluginAll 应用所有拦截器,得到代理后的对象。供后续流程使用。 pluginall迭代调用所有插件的plugin方法。
    1. Plugin提供工具方法wrap用于,生成传入对象的动态代理。 第一个参数为 被代理对象。第二个参数为 Interceptor (plugin)对象本身。
    1. 当拦截方法调用时,会执行Interceptor的intercept方法,传入的Invocation 对象 封装了代理方法的调用过程,通过调用proceed方法 使之执行。

binding

生成mapper接口的 动态代理。
实现方式与 retrofit 相同。 https://www.jianshu.com/p/122859d42f4f

    1. MapperProxyFactory<T> 用于生成mapper的动态代理对象。
    1. MapperProxy<T> mapper的动态代理。保存了接口中的所有方法map methodCache。
@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

接口调用时invoke根据传入的method 在methodCache中查找方法,调用MapperMethod.execute()

    1. MapperMethod 根据 interface method 到configuration中找到MappedStatement。根据MappedStatement的类型,query,insert,update,delete 在execute时 将方法路由到sqlsession 相应的实现上。

executor

sql的执行器,封装了对jdbc的调用。
sqlsession调用executor实现 对底层sql的执行。

    1. statement 子包, 封装了jdbc Statement 对象 的执行。StatementHandler接口。

mybatis-spring 源码流程

    1. SqlSessionTemplate类
      线程安全的SqlSession实现
      使用内部类SqlSessionInterceptor作为动态代理,invoke调用时
      首先从事务管理器获取sqlsession,如果是在一个事务中则sql是ThreadLocal中存储的sqlsession。
      如果不在事务中,则通过sqlSessionFactory.openSession()新创建一个sqlsession对象。
      最后调用registerSessionHolder(sqlsession) , 如果开启事务,将sqlsession注册。

transaction

实现mybatis包中的事务接口, 提供 spring 管理的 事务。
使用了 spring-jdbc spring-tx

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • # Awesome Python [![Awesome](https://cdn.rawgit.com/sindr...
    emily_007阅读 2,165评论 0 3
  • # Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列...
    小迈克阅读 2,921评论 1 3
  • 产品经理入门最大的问题,就是不知道学什么。 当经过一段摸索后知道学什么后,可能碰到的最大问题有可能是缺乏系统安排、...
    小徐同学阅读 14,748评论 5 90
  • Materials CPR keeps blood and oxygen flowing to the heart...
    Mere_G阅读 136评论 0 0
  • 二三十年来,细数一路长大的历程,迄今为止,大多数人所经历的互联网事件可谓不少,这些事物吸引着我们的注意力和精力,让...
    烈焰神马阅读 679评论 0 2