【mybatis源码】Mapper的动态代理

DefaultSqlSession的getMapper方法入手:
(1)DefaultSqlSession的getMapper方法中实际上又调用的是Configuration中的getMapper方法:
@Override
public <T> T getMapper(Class<T> type) {
  return configuration.<T>getMapper(type, this);
}
(2)Configuration中的getMapper方法中接着调用MapperRegistry的getMapper方法:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
  return mapperRegistry.getMapper(type, sqlSession);
}
(3)MapperRegistry的getMapper方法
knowMappers:已知的mapper集合,MapperRegistry类中有一系列的addMapper方法,将Mapper加入集合
getMapper():根据传入的class对象从已知的mapper集合中查找,如果查找失败抛出异常,如果查找成功,获取该class对象的vlaue,是一个

MapperProxyFactory类型,然后调用mapperProxyFactory.newInstance(sqlSession)方法,创建mapper的实例。

public class MapperRegistry {

  private final Configuration config;
  /**
   * 已知的Mapper集合,有添加mapper的方法,通过添加方法,将所有的Mapper接口添加到已知集合里
   * key:Mapper接口的class对象
   * value:MapperProxyFactory,从名字上看是一个mapper代理工厂
   */
  private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();

  public MapperRegistry(Configuration config) {
    this.config = config;
  }

  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //根据Class类型从已知的mapper集合中查找
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    //如果查找失败抛出异常
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      //动态代理创建一个mapper的实例
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
  
  public <T> boolean hasMapper(Class<T> type) {
    return knownMappers.containsKey(type);
  }

  /**
   * 添加mapper
   * @param type
   * @param <T>
   */
  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 {
        //将mapper放入knownMappers中
        knownMappers.put(type, new MapperProxyFactory<T>(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);
        }
      }
    }
  }

  /**
   * @since 3.2.2
   */
  public Collection<Class<?>> getMappers() {
    return Collections.unmodifiableCollection(knownMappers.keySet());
  }

  /**
   * @since 3.2.2
   */
  public void addMappers(String packageName, Class<?> superType) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
  }

  /**
   * 通过扫描包名向knownMappers添加mapper
   * @since 3.2.2
   */
  public void addMappers(String packageName) {
    addMappers(packageName, Object.class);
  }
  
}

(4)MapperProxyFatory的newInstance方法

调用newInstance(sqlSession)方法时,会生成一个MapperProxy对象,从名字就能看出,这就是Mapper的代理类,然后再调用Proxy.newProxyInstance完成代理对象的实例化。

public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final 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) {
    /**
     * 使用动态代理实例化代理对象
     * 三个参数:
     * 1:指明生成代理对象使用哪个类加载器
     * 2:指明生成哪个对象的代理对象,通过接口指定
     * 3:代理对象,MapperProxy实现了InvocationHandler接口
     */
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    //创建一个 MapperProxy对象
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    //使用动态代理实例化对象
    return newInstance(mapperProxy);
  }

}

(5)mapper的实际代理对象MapperProxy

可以看出MapperProxy实现了InvocationHandler接口,重写了invoke方法。

调用Mapper中的方法时,会调用invoke方法,invoke方法需要三个参数,proxy指的是代理对象,method指的是调用被代理对象中的方法,args是方法的参数。

在inoke方法中,通过方法获取方法所在类的class信息,如果是个接口,会将被调用的方法封装为一个MapperMethod对象,然后调用它的execute方法。

/**
 * mapper的代理类
 */
public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -6424540398559729838L;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  /**
   * 方法缓存集合,当调用接口中的方法时,会将封装一个MapperMethod对象做为value,方法作为key,放入集合中
   */
  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;
  }

  /**
   * 通过动态代理调用被代理对象的方法时,实际走的是invoke方法,在invoke方法中通过method.invoke方式完成方法的调用
   * @param proxy
   * @param method
   * @param args
   * @return
   * @throws Throwable
   */
  @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 if (isDefaultMethod(method)) {//是否是默认的方法
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //如果是接口,通过cachedMapperMethod方法完成MapperMethod的实例化
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    //如果不在方法缓存中
    if (mapperMethod == null) {
      //创建一个MapperMethod对象
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

  @UsesJava7
  private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
      throws Throwable {
    final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
        .getDeclaredConstructor(Class.class, int.class);
    if (!constructor.isAccessible()) {
      constructor.setAccessible(true);
    }
    final Class<?> declaringClass = method.getDeclaringClass();
    return constructor
        .newInstance(declaringClass,
            MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
                | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
        .unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
  }

  /**
   * 默认的方法
   */
  private boolean isDefaultMethod(Method method) {
    return (method.getModifiers()
        & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
        && method.getDeclaringClass().isInterface();
  }
}

(6)MapperMethod类

MapperMethod构造函数中会对SqlCommand对象和MethodSignature对象初始化。SqlCommand中封装了SQL命令类型以及方法的名称(XML中配置的id+Mapper所在接口路径),MethodSignature中封装了方法参数、返回类型等信息。

在SqlCommand初始化时,又根据接口和调用的方法信息创建了MappedStatement对象,封装了XML当中标签的信息。

执行MapperMethod的execute方法时先判断SQL命令类型(增删改查等),然后调用的是SqlSession中的方法执行SQL命令。

public class MapperMethod {

  /**
   * 封装了SQL命令类型(增删改查等)
   */
  private final SqlCommand command;
  /**
   * 封装了方法参数、返回类型等信息
   */
  private final MethodSignature method;

  /**
   * 构造函数
   * @param mapperInterface
   * @param method
   * @param config
   */
  public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    //初始化SqlCommand
    this.command = new SqlCommand(config, mapperInterface, method);
    //初始化MethodSignature
    this.method = new MethodSignature(config, mapperInterface, method);
  }

  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判断SQL标签类型
    switch (command.getType()) {
      case INSERT: {//插入
      Object param = method.convertArgsToSqlCommandParam(args);//处理参数
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {//更新
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {//删除
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT://查找
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {//返回多条数据
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {//返回类型是Map
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {//返回游标
          result = executeForCursor(sqlSession, args);
        } else {//返回单行数据
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

......

  /**
   * 返回多条数据的查询方法
   * @param sqlSession
   * @param args
   * @param <E>
   * @return
   */
  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    //处理参数
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {//如果是分页查询
      RowBounds rowBounds = method.extractRowBounds(args);
      //调用sqlSession的方法执行查询
      result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
    } else {
      result = sqlSession.<E>selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      if (method.getReturnType().isArray()) {
        return convertToArray(result);
      } else {
        return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
      }
    }
    return result;
  }

......
 
  public static class SqlCommand {

    /**
     * XML标签中ID + Mapper所在类/接口的路径
     */
    private final String name;
    /**
     *  SQL命令类型
     *  包含了UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH;
     */
    private final SqlCommandType type;

    /**
     * 构造函数
     * @param configuration
     * @param mapperInterface
     * @param method
     */
    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
      final String methodName = method.getName();//方法名
      final Class<?> declaringClass = method.getDeclaringClass();//方法所在类/接口的class对象
      //创建MappedStatement对象,这个对象封装了XML当中标签的信息
      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
          configuration);
      if (ms == null) {
        if (method.getAnnotation(Flush.class) != null) {
          name = null;
          type = SqlCommandType.FLUSH;
        } else {
          throw new BindingException("Invalid bound statement (not found): "
              + mapperInterface.getName() + "." + methodName);
        }
      } else {
        name = ms.getId();
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }

    public String getName() {
      return name;
    }

    public SqlCommandType getType() {
      return type;
    }

    private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
        Class<?> declaringClass, Configuration configuration) {
      //statementId,是方法名+类/接口的完整路径 eg:org.mybatis.example.BlogMapper.selectBlog
      String statementId = mapperInterface.getName() + "." + methodName;
      //如果Configuration中已经存在
      if (configuration.hasStatement(statementId)) {
        //直接从初始化阶段生成的mappedStatements中,获取当前SQL语句的mappedStatement
        return configuration.getMappedStatement(statementId);
      } else if (mapperInterface.equals(declaringClass)) {
        /*
         * mapperInterface如果是接口应该是interface 包名.接口名,declaringClass是包名.接口名
         * 还不清楚什么情况下mapperInterface和declaringClass相同,反正就是如果它们两个相同就返回null
         */
        return null;
      }
      //如果初始化阶段还没有加载过,找到当前方法所在的接口,getInterfaces()获取这个对象实现的所有接口
      for (Class<?> superInterface : mapperInterface.getInterfaces()) {
        if (declaringClass.isAssignableFrom(superInterface)) {
          //生成MappedStatement
          MappedStatement ms = resolveMappedStatement(superInterface, methodName,
              declaringClass, configuration);
          if (ms != null) {
            return ms;
          }
        }
      }
      return null;
    }
  }

  public static class MethodSignature {

    private final boolean returnsMany;//返回多条结果
    private final boolean returnsMap;//返回Map
    private final boolean returnsVoid;//返回空
    private final boolean returnsCursor;//返回游标
    private final Class<?> returnType;//返回类型
    private final String mapKey;
    private final Integer resultHandlerIndex;//resultHandler类型参数的位置
    private final Integer rowBoundsIndex;//rowBound类型参数的位置
    private final ParamNameResolver paramNameResolver;//参数处理类

    public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      this.returnsVoid = void.class.equals(this.returnType);
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }

......
    private Integer getUniqueParamIndex(Method method, Class<?> paramType) {
      Integer index = null;
      final Class<?>[] argTypes = method.getParameterTypes();
      for (int i = 0; i < argTypes.length; i++) {
        if (paramType.isAssignableFrom(argTypes[i])) {
          if (index == null) {
            index = i;
          } else {
            throw new BindingException(method.getName() + " cannot have multiple " + paramType.getSimpleName() + " parameters");
          }
        }
      }
      return index;
    }

    private String getMapKey(Method method) {
      String mapKey = null;
      if (Map.class.isAssignableFrom(method.getReturnType())) {
        final MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
        if (mapKeyAnnotation != null) {
          mapKey = mapKeyAnnotation.value();
        }
      }
      return mapKey;
    }
  }

}

参考:

MyBatis 源码分析——动态代理

Mybatis中Mapper动态代理的实现原理

mybatis源码分析5 - mapper读写数据库完全解析

Java基础加强总结(三)——代理(Proxy)




猜你喜欢

转载自blog.csdn.net/lom9357bye/article/details/80207074