2018-03-29 MyBatis Mapper原理浅析

思考问题:Mapper是定义的接口,如何完成代码实现的?

其实在业务代码使用的Mapper并不是自己所建立的Mapper接口,而是通过MyBatis的
MapperProxyFactory.newInstance(sqlSession);动态代理生成的MapperProxy的代理对象。

/**
* 映射器代理工厂
*/
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) {
   //用JDK自带的动态代理生成映射器
   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);
 }

}
思考问题:MapperProxy代理对象又是什么呢?

想了解MapperProxy,需要先了解Java的动态代理技术。
MapperProxy通过重写invoke方法,完成Mapper接口的示例化。

/**
 * 映射器代理,代理模式
 *
 */
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;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //代理以后,所有Mapper的方法调用时,都会调用这个invoke方法
    //并不是任何一个方法都需要执行调用代理对象进行执行,如果这个方法是Object中通用的方法(toString、hashCode等)无需执行
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    //这里优化了,去缓存中找MapperMethod
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //执行
    return mapperMethod.execute(sqlSession, args);
  }

  //去缓存中找MapperMethod
  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      //找不到才去new
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,872评论 0 4
  • 1 引言# 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybait...
    七寸知架构阅读 76,743评论 36 979
  • 单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用sp...
    七寸知架构阅读 3,523评论 0 53
  • 前面的章节主要讲mybatis如何解析配置文件,这些都是一次性的初始化过程。从本章开始讲解动态的过程,它们跟应用程...
    七寸知架构阅读 5,007评论 2 55
  • 前几天收到一个小妹妹发来的微信,她说记得我曾经说过这样一句话:心有多大舞台就有多大,为什么十年过去了,她的人生一点...
    冰叶草阅读 479评论 3 3