从上图可能看出,在 mybatis中,SqlSession的实现类有两个,其中SqlSessionManager类不但实现了SqlSession接口,同时也实现了SqlSessionFactory接口。那么SqlSessionManager类究竟有何作用 ? 由于源码中缺少注释,所以从mybatis目前的提供官方文档来看,似乎该类已被弃用,其功能被DefaultSqlSession类和DefaultSqlSessionFactory类所代替。只是该类的部分代码对我们理解mybatis的一些底层机制还具有一定的参考价值,例如:

SqlSessionManager的下面的构造方法,会产生一个SqlSession的一个代理对象:

private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}

SqlSessionInterceptor类实现了InvocationHandler接口

privaprivate class SqlSessionInterceptor implements InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
final SqlSession autoSqlSession = openSession();
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
} finally {
autoSqlSession.close();
}
}
}
}
private class SqlSessionInterceptor implements InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
if (sqlSession != null) {
try {
return method.invoke(sqlSession, args);
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
} else {
final SqlSession autoSqlSession = openSession();
try {
final Object result = method.invoke(autoSqlSession, args);
autoSqlSession.commit();
return result;
} catch (Throwable t) {
autoSqlSession.rollback();
throw ExceptionUtil.unwrapThrowable(t);
} finally {
autoSqlSession.close();
}
}
}
}

下面对这一段使用JAVA动态代理技术产生SqlSession代理对象的代码进行分析:

this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(

SqlSessionFactory.class.getClassLoader(),

new Class[]{SqlSession.class},

new SqlSessionInterceptor())  这句是关键,JDK的Proxy类的newProxyInstance方法的方法原型如下:

public static Object newProxyInstance(ClassLoader loader,

Class<?>[] interfaces,

InvocationHandler h)

throws IllegalArgumentException

在调这个方法中需要传入三个参数:

Ø 一个interfaces的数组参数

Ø 一个InvocationHanler 接口的实例对象

Ø 一个类加载器,

则Proxy.newProxyInstance方法执行后会返回interfaces中任一接口的实例对象(假设该对象为proxyObject),那么当我们在调用这个对象proxyObject的相应方法时,就会进入到InvocationHandler 这个参数对象的invoke(Object proxy, Method method, Object[] args)方法中,或者换句话说,就会被h这个对象的invoke方法拦截, 对象proxyObject会作为

Invoke中的proxy参数,proxyObject调用的方法的方法对象会作为method参数,方法的参数会作为args参数,这样在InvocationHandler 对象的invoke方法中,就会通过Method.invoke方法来执行具体的目标对象的相应方法,在mybatis的这个应用场景上,这个目标对象其实就是一个SqlSession的实例,通过SqlSessionManager类的成员变量sqlSessionFactory的openSession()获得或者从当前线程中获取。

以上的实现技术主要就是使用了java的动态代理技术,看到网上不少人在问这个InvocationHandler 接口中的invoke方法的第一个参数proxy究竟有何作用,这个proxy其实就是一个代理对象实例(通过Proxy.newProxyInstance方法产生),下面就举例说明一下它的作用:

可参照 java.rmi.server.RemoteObjectInvocationHandler类中的相应方法invoke方法,一个用法就是判断invoke的method参数,看是否有必要调用proxy对象的其他方法,另一个用处就是作为参数把该对象提供给远程调用的方法使用。

mybatis源码分析(3)——SqlSessionManager类的更多相关文章

  1. 精尽MyBatis源码分析 - MyBatis-Spring 源码分析

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

  2. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

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

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

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

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

  5. MyBatis源码分析(3)—— Cache接口以及实现

    @(MyBatis)[Cache] MyBatis源码分析--Cache接口以及实现 Cache接口 MyBatis中的Cache以SPI实现,给需要集成其它Cache或者自定义Cache提供了接口. ...

  6. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  7. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  8. MyBatis源码分析之环境准备篇

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

  9. Mybatis源码分析-BaseExecutor

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

随机推荐

  1. c#简体繁体转换

     方法一已经亲测,使用正常,方法二貌似不能用. 方法一 /// <summary> /// 中文字符工具类 /// </summary> public static class ...

  2. C#中2、8、16进制 有符号转换10进制正负数

    曾经让我苦想的其他进制转有符号整型问题,结果自己想到方法解决后才发现原来如此简单. 1.Int16(2个byte长度 ) : 方法 :Convert.ToInt16(进制编码,进制) a.16进制转1 ...

  3. js使用正则表达式去空格

    写成类的方法格式如下:(str.trim();) <script language="javascript"> String.prototype.trim=functi ...

  4. 10.20_wiki

    XWiki:官网.Documentation.User's GuideProgrammer's GuideAdministrator's Guide Developer's Guide (1) htt ...

  5. CentOS7设置IP地址

    root权限下cd到/etc/sysconfig/network-scripts, vi ifcig-em1 TYPE=Ethernet BOOTPROTP=static NAME=em1 UUID= ...

  6. Demo_张仕传_结构体考试-modify

    /* 题目: //声明一个结构体类型 struct _AdvTeacher { char *name; char *tile; int age; char *addr; char *p1; //系统预 ...

  7. 安装会声会影x8后打不开的解决方法

    操作系统:Windows 7 症状:双击程序图标后一直停留在购买介绍页,主程序界面一直无法打开 解决方法:删除系统补丁KB3126587和KB3126593

  8. SQL 添加字段和默认值脚本

    --插入字段和默认值alter table Acc_WayBill add DeclaredValue nvarchar(50)goEXEC sys.sp_addextendedproperty @n ...

  9. C#事件作用和用法

    例如有下面的需求需要实现:程序主画面中弹出一个子窗口.此时主画面仍然可以接收用户的操作(子窗口是非模态的).子窗口上进行某些操作,根据操作的结果要在主画面上显示不同的数据. 即如下图所示: 大多数我们 ...

  10. js异步脚本

    1.延迟脚本 HTML4.01为<script>标签定义了defer属性,为了表明脚本在执行时不会影响页面的构造.也就是说,脚本会在整个页面都解析完毕后再运行.因此在<script& ...