美文网首页
Mybatis之Mapper

Mybatis之Mapper

作者: 圣村的希望 | 来源:发表于2018-06-29 09:42 被阅读0次

    mybatis中mapper都是接口,我们在使用的时候都是可以通过@Autowired依赖注入进mapper实例。这些mapper实例都是由MapperProxyFactory工厂生成的MapperProxy代理对象,这里主要涉及到了Mapper、MapperProxy和MapperProxyFactory三个对象,以下是对这些对象的简要描述:

    • Mapper:这个是我们定义的Mapper接口,在应用中使用。
    • MapperProxy:这个是使用JDK动态代理对Mapper接口生成的代理实例,也就是我们实际使用引入的实例对象
    • MapperProxyFactory:这个是使用了工厂模式,用来对某一mapper接口来生成MapperProxy实例的。

    以下来对上述接口和类来进行源码分析:

    MapperProxyFactory源码:

    public class MapperProxyFactory<T> {
      //mapper接口,就是实际我们定义的接口,也是需要代理的target
      private final Class<T> mapperInterface;
      //Method的缓存,应该是当前Mapper里面的所有method,这里有点疑问
      private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<>();
    
      //给对应的mapper接口生成MapperProxy代理对象
      @SuppressWarnings("unchecked")
      protected T newInstance(MapperProxy<T> mapperProxy) {
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
      }
    
      public T newInstance(SqlSession sqlSession) {
        final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
        return newInstance(mapperProxy);
      }
    }
    

    MapperProxy源码:

    public class MapperProxy<T> implements InvocationHandler, Serializable {
      //当前会话
      private final SqlSession sqlSession;
      //target对象,mapper接口
      private final Class<T> mapperInterface;
      //方法缓存,key是Mapper接口里面的Method对象
      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 {
        try {
          //判断方法是否为Obect里面声明的对象
          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);
        }
        //创建并缓存MapperMethod
        final MapperMethod mapperMethod = cachedMapperMethod(method);
        //执行method方法
        return mapperMethod.execute(sqlSession, args);
      }
    
      private MapperMethod cachedMapperMethod(Method method) {
      //如果缓存里面没有的话就创建并且放入缓存中,这里缓存是一个ConcurrentHashMap
        return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
      }
    }
    

    这里的MapperProxy是对Mapper接口的代理对象,当调用mapper接口的方法时会进行拦截,生成MapperMethod对象并放入缓存中,这里的缓存存在的意义就是不用下次再来生成该接口方法的MapperMethod对象,然后执行对应的方法。这里根据方法类型(insert | update)来路由执行对应的方法。

    Mapper接口内的方法不能重载

    原因:在Mapper接口生成的代理MapperProxy中,可以看到在方法被拦截的处理动作中,是把方法对应的MapperMethod放到了缓存中,缓存是以Method对象作为key,所以是不允许重载这种情况的。

    final MapperMethod mapperMethod = cachedMapperMethod(method);
    

    相关文章

      网友评论

          本文标题:Mybatis之Mapper

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