Mybatis系列之三 MapperProxy(揭示Mapper类背后的执行逻辑)

一、思路

背景: mybatis 3.2.8+spring 4.3.2

  1. mapper的初始化过程。
  2. MapperProxy的执行过程。

二、mapper的初始化过程

请参考上一篇博客Mybatis系列之MapperRegister,关于spring是如何获取mapper对象的,这里就不赘述了。

三、MapperProxy的执行过程

我们用一个小例子来讲解,我们从spring上下文中拿到PersonMapper这个bean,然后调用它的count()方法,拿到结果输出到控制台。

PersonMapper

public interface PersonMapper {
    int count();
}

PersonMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.com.bsfit.mapper.PersonMapper">
    <select id="count" resultType="int">
          select count(1) from t1
    </select>
</mapper>

Main

    @Test
    public void testBeanGet() {
        ApplicationContext context = new FileSystemXmlApplicationContext("classpath:spring.xml");
        PersonMapper mapper = (PersonMapper) context.getBean("personMapper");
        int count = mapper.count();
        System.out.println(count);
    }

说完上面的例子后,我们就来分析它背后的执行原理。
根据 第二节的信息我们知道我们拿到PersonMapper的Bean是一个PersonMapper接口的实现类,而这个实现类就是MapperProxy的一个代理类。拿到这个bean后,可以在控制台输出mapper.getClass()结果观察下,会发现它类似下面的输出,是一个JDK的代理类。

com.sun.proxy.$Proxy10

我们在看一下MapperProxy类的类结构,它实现了InvocationHandler接口,这个接口正是JDK代理类所需要实现的,代理类真正执行方法的时候会调用MapperProxy实现的 public Object invoke(Object proxy, Method method, Object[] args) 方法

MapperProxy类结构

下面我们来分析下MapperProxy实现的invoke方法,根据调用的mapper的方法找到对应的MapperMethod实例,之后开始真正执行sql。

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 如果mapper调用的方法是object类声明的,则直接调用。
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    // 根据要调用的mapper方法(在我们的例子中是count())查询应对的MapperMethod实例
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    // 获取到MapperMethod实例后,开始真正的执行sql
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    // 这里做了一层MapperMethod的缓存
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }
}

好了,到这里就结束了今天分享,下次我们再来看看MapperMethod具体是怎么来执行sql的。

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

推荐阅读更多精彩内容