关于前端:聊聊Mybatis的binding模块

聊聊Mybatis的binding模块

为什么咱们在应用Mybatis的时候只须要写接口和xml文件就能执行sql呢?这就是Mybatis的binding模块须要做的事件了,明天咱们剖析一下Mybatis的binding模块,binding包下的类次要有四个MapperRegistry、MapperProxyFactory、MapperProxy和MapperMethod
映射注册类MapperRegistry

MapperRegistry是个注册类,它的knownMappers汇合保留着Mapper接口和MapperProxyFactory实例的映射关系

它的addMapper()办法就是增加映射关系的办法:

public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        knownMappers.put(type, new MapperProxyFactory<>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

当传入的type是个接口并knownMappers中没有,就把type和对应的MapperProxyFactory实例放入knownMappers中

而后在执行sql的时候,Mybatis会调用MapperRegistry.getMapper()办法

@SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
先从knownMappers汇合中找到对应的MapperProxyFactory实例

而后调用newInstance()办法
映射代理工厂类MapperProxyFactory

MapperProxyFactory的newInstance()办法:
public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

生成mapperInterface接口 的代理对象的实例,代理类是MapperProxy,它实现了InvocationHandler,利用jdk动静代理生成代理对象

看一下它重写的invoke()办法:
映射代理类MapperProxy

MapperProxy的invoke()办法:

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else {
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

不是Object的类会被拦挡,拦挡调用cachedInvoker()办法,其余执行invoke()办法,

private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {
      return MapUtil.computeIfAbsent(methodCache, method, m -> {
        if (m.isDefault()) {
          try {
            if (privateLookupInMethod == null) {
              return new DefaultMethodInvoker(getMethodHandleJava8(method));
            } else {
              return new DefaultMethodInvoker(getMethodHandleJava9(method));
            }
          } catch (IllegalAccessException | InstantiationException | InvocationTargetException
              | NoSuchMethodException e) {
            throw new RuntimeException(e);
          }
        } else {
          return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
        }
      });
    } catch (RuntimeException re) {
      Throwable cause = re.getCause();
      throw cause == null ? re : cause;
    }
  }
从methodCache中获取对应的MapperMethodInvoker

如果缓存没有,如果是办法是default办法就创立DefaultMethodInvoker对象,否则创立PlainMethodInvoker对象
默认办法调用类DefaultMethodInvoker

对于DefaultMethodInvoker类通过MethodHandle实现调用
private static class DefaultMethodInvoker implements MapperMethodInvoker {
    private final MethodHandle methodHandle;

    public DefaultMethodInvoker(MethodHandle methodHandle) {
      super();
      this.methodHandle = methodHandle;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      return methodHandle.bindTo(proxy).invokeWithArguments(args);
    }
  }

对于一般办法对应的类PlainMethodInvoker通过MapperMethod来实现调用,

private static class PlainMethodInvoker implements MapperMethodInvoker {
    private final MapperMethod mapperMethod;

    public PlainMethodInvoker(MapperMethod mapperMethod) {
      super();
      this.mapperMethod = mapperMethod;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
      return mapperMethod.execute(sqlSession, args);
    }
  }

总结

这篇文章次要介绍了聊聊Mybatis的binding模块,它的MapperRegistry保留着Mapper接口和MapperProxyFactory实例的映射关系,而MapperProxyFactory是一个的工厂,生成的是Mapper接口的代理类,MapperProxy实现InvocationHandler,重写invoke()办法进行拦挡解决,依据办法判断是不是default类型创立不同的MethodInvoker类,而后调用MapperMethod执行sql,下篇文章咱们将介绍MapperMethod类

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理