美文网首页
Mybatis系列之三 MapperProxy(揭示Mapper

Mybatis系列之三 MapperProxy(揭示Mapper

作者: 超人也害羞 | 来源:发表于2019-07-17 00:14 被阅读0次

    一、思路

    背景: 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的。

    相关文章

      网友评论

          本文标题:Mybatis系列之三 MapperProxy(揭示Mapper

          本文链接:https://www.haomeiwen.com/subject/ivtflctx.html