MyBatis印象阅读之反射工具扩展

2019-07-24  本文已影响0人  向光奔跑_

在本篇中,我们暂且不还之前的债

  • Configuration
  • TypeAliasRegistry
  • TypeHandlerRegistry
    而是对之前反射包下的类做补充说明。

回顾一下,之前我们介绍了MyBatis框架下的refection包:


MyBatis下的refection包

在其中我们介绍了DefaultObjectFactory、DefaultReflectorFactory、Reflector。大家对其他的类可能有充满了好奇,所以本章是作为补充。

可能会问这个和主流程相关么?看这个源码有什么好处么?

回答是和主流程不相关,但是主流程中大量用了这些辅助类用来简化操作,如果不看懂,那主流程源码会是雾里看花,所谓磨刀不误砍柴工,所以今天我就来介绍几个在主流程源码上经常使用的类。

1.TypeParameterResolver源码解析

这里我们还是借助于官方源码提供的测试类TypeParameterResolverTest,一个好的类名可以让我们不看起内部而知道其意,看这个方法,我们猜测应该是和参数类型解析有关,那么我们先来看一个测试类中的测试方法:

 // TypeParameterResolverTest

  @Test
  void testReturn_Lv0SimpleClass() throws Exception {
    Class<?> clazz = Level0Mapper.class;
    Method method = clazz.getMethod("simpleSelect");
    Type result = TypeParameterResolver.resolveReturnType(method, clazz);
    assertEquals(Double.class, result);
  }

```java
public interface Level0Mapper<L, M, N> {

  Double simpleSelect();

  。。。

  interface Level0InnerMapper extends Level0Mapper<String, Long, Float> {
  }

}

感觉这样子是不是和我们平常使用MyBatis有点联系了?都是接口。 我们继续往下看,因为TypeParameterResolver是辅助方法,内部都是静态方法,所以我们不分析起属性和构造函数,直接杀入调用方法:

 //TypeParameterResolver
  
  /**
   * @return The return type of the method as {@link Type}. If it has type parameters in the declaration,<br>
   *         they will be resolved to the actual runtime {@link Type}s.
   */
  public static Type resolveReturnType(Method method, Type srcType) {
    Type returnType = method.getGenericReturnType();
    Class<?> declaringClass = method.getDeclaringClass();
    return resolveType(returnType, srcType, declaringClass);
  }
  
    /**
      * 解析类型
      */
  private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
    if (type instanceof TypeVariable) {
      return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
    } else if (type instanceof ParameterizedType) {
      return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
    } else if (type instanceof GenericArrayType) {
      return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
    } else {
      return type;
    }
  }

这里按照这个规则,看到上述是Double,在判断type类型时,我们直接到了最下面一层,也就是直接返回。

我们来看继续下一个测试案例,首先是我们的Level0Mapper类方法:


 //Level0Mapper
 List<Double> simpleSelectList();

之后再来看继承关系Level1Mapper继承Level0Mapper方法:

public interface Level1Mapper<E, F> extends Level0Mapper<E, F, String> {
}

最后来看我们的测试案例:

  @Test
  void testReturn_SimpleList() throws Exception {
    Class<?> clazz = Level1Mapper.class;
    Method method = clazz.getMethod("simpleSelectList");
    Type result = TypeParameterResolver.resolveReturnType(method, clazz);
    assertTrue(result instanceof ParameterizedType);
    ParameterizedType paramType = (ParameterizedType) result;
    assertEquals(List.class, paramType.getRawType());
    assertEquals(1, paramType.getActualTypeArguments().length);
    assertEquals(Double.class, paramType.getActualTypeArguments()[0]);
  }

这里可能会对ParameterizedType有疑问,认为这是什么类?充满了疑惑,这里简单介绍下:
ParameterizedType是Java解析泛型反射的类,我们看到上述接口返回应该是LIst<Double>,而Double是泛型。我们直接来看下上面那个方法对于泛型的处理,可能会有帮助理解:

  private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
    Class<?> rawType = (Class<?>) parameterizedType.getRawType();
    Type[] typeArgs = parameterizedType.getActualTypeArguments();
    Type[] args = new Type[typeArgs.length];
    for (int i = 0; i < typeArgs.length; i++) {
      if (typeArgs[i] instanceof TypeVariable) {
        args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
      } else if (typeArgs[i] instanceof ParameterizedType) {
        args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
      } else if (typeArgs[i] instanceof WildcardType) {
        args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
      } else {
        args[i] = typeArgs[i];
      }
    }
    return new ParameterizedTypeImpl(rawType, null, args);
  }

我们可以看下这个内部类ParameterizedTypeImpl

static class ParameterizedTypeImpl implements ParameterizedType {
    private Class<?> rawType;

    private Type ownerType;

    private Type[] actualTypeArguments;

    public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
      super();
      this.rawType = rawType;
      this.ownerType = ownerType;
      this.actualTypeArguments = actualTypeArguments;
    }

    @Override
    public Type[] getActualTypeArguments() {
      return actualTypeArguments;
    }

    @Override
    public Type getOwnerType() {
      return ownerType;
    }

    @Override
    public Type getRawType() {
      return rawType;
    }

    @Override
    public String toString() {
      return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments=" + Arrays.toString(actualTypeArguments) + "]";
    }
  }

我们只需要熟悉ParameterizedType,方法逻辑不难理解。List可类比Map类型,这里不做展开。这里我们就分析这两种,其实只需知道这个方法类是用来解析返回类型即可。具体细节可有需要在深入。

2.MetaClass源码解析

下面我们来分析refection包下的MetaClass类,那么这个类是干什么的呢?见名知意起应该是存储类元信息的,我们来揭开它的面纱。我们继续从test方法入手,先从MetaClassTest中的第一个Test方法开始撸:

  @Test
  void shouldTestDataTypeOfGenericMethod() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(GenericConcrete.class, reflectorFactory);
    assertEquals(Long.class, meta.getGetterType("id"));
    assertEquals(Long.class, meta.getSetterType("id"));
  }

那么我们跟随进入MetaClass.forClass方法:

public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
    return new MetaClass(type, reflectorFactory);
  }

   
   /**
   * 我们可以看出这里就是ReflectorFactory和创建Reflector
   */
  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type);
  }

我这边也来总结一下,有利于让你更好的理解:

MetaClass是对Reflector的封装,使用装饰者模式。

具体我们可以来看下meta的getGetterType方法:

public Class<?> getGetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaClass metaProp = metaClassForProperty(prop);
      return metaProp.getGetterType(prop.getChildren());
    }
    // issue #506. Resolve the type inside a Collection Object
    return getGetterType(prop);
  }
 
   /**
   * 获取属性对应类型,并进行构建MetaClass返回
   */
 private MetaClass metaClassForProperty(PropertyTokenizer prop) {
    Class<?> propType = getGetterType(prop);
    return MetaClass.forClass(propType, reflectorFactory);
  }
  
  /**
   * 从reflector中获取对应name的类类型
   */
 private Class<?> getGetterType(PropertyTokenizer prop) {
    Class<?> type = reflector.getGetterType(prop.getName());
    if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
      Type returnType = getGenericGetterType(prop.getName());
      if (returnType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
        if (actualTypeArguments != null && actualTypeArguments.length == 1) {
          returnType = actualTypeArguments[0];
          if (returnType instanceof Class) {
            type = (Class<?>) returnType;
          } else if (returnType instanceof ParameterizedType) {
            type = (Class<?>) ((ParameterizedType) returnType).getRawType();
          }
        }
      }
    }
    return type;
  }

这里的逻辑暂且不谈,我们先来看这里又引入的PropertyTokenizer类。

2.1 PropertyTokenizer类方法解析

我们继续来看他的属性和构造方法:

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  private String name;
  private final String indexedName;
  private String index;
  private final String children;

  /**
  * 这里的作用是解析层级关系
  * 例: fullname=richType.richList[0]
  * 则第一层name = richType, children = richList[0],别的为null
  * 第二层name = richList, indexedName = richList[0], index = 0
  */
  public PropertyTokenizer(String fullname) {
    int delim = fullname.indexOf('.');
    if (delim > -1) {
      name = fullname.substring(0, delim);
      children = fullname.substring(delim + 1);
    } else {
      name = fullname;
      children = null;
    }
    indexedName = name;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }

  public String getName() {
    return name;
  }

  public String getIndex() {
    return index;
  }

  public String getIndexedName() {
    return indexedName;
  }

  public String getChildren() {
    return children;
  }

  @Override
  public boolean hasNext() {
    return children != null;
  }

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
  }
}

在上面的注释中,我把逻辑写的比较详细了,就是递归解析参数。这里我们可以了解到我们之前使用richType.richList[0]这里能解析进去都是靠这个辅助类的帮助。

2.2 MetaClass的getGetterType方法分析


  /**
   * 从reflector中获取对应name的类类型
   */
  private Class<?> getGetterType(PropertyTokenizer prop) {
    //这里的prop会递归调用到最后一层,这一步可以拿到prop的get方法
    Class<?> type = reflector.getGetterType(prop.getName());
    if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
      Type returnType = getGenericGetterType(prop.getName());
      if (returnType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
        if (actualTypeArguments != null && actualTypeArguments.length == 1) {
          returnType = actualTypeArguments[0];
          if (returnType instanceof Class) {
            type = (Class<?>) returnType;
          } else if (returnType instanceof ParameterizedType) {
            type = (Class<?>) ((ParameterizedType) returnType).getRawType();
          }
        }
      }
    }
    return type;
  }
  
  
   /**
   * 解析列表类型
   */
private Type getGenericGetterType(String propertyName) {
    try {
      //获取属性的Get方法执行器
      Invoker invoker = reflector.getGetInvoker(propertyName);
      // 通过invoker获取对应属性,这里MethodInvoker、GetFieldInvoker的作用就是取属性
     // 无非一个是通过Get方法调用获取,一个是直接属性反射获取
      if (invoker instanceof MethodInvoker) {
        Field _method = MethodInvoker.class.getDeclaredField("method");
        _method.setAccessible(true);
        Method method = (Method) _method.get(invoker);
        return TypeParameterResolver.resolveReturnType(method, reflector.getType());
      } else if (invoker instanceof GetFieldInvoker) {
        Field _field = GetFieldInvoker.class.getDeclaredField("field");
        _field.setAccessible(true);
        Field field = (Field) _field.get(invoker);
        return TypeParameterResolver.resolveFieldType(field, reflector.getType());
      }
    } catch (NoSuchFieldException | IllegalAccessException ignored) {
    }
    return null;
  }

帮大家梳理一下逻辑。meta.getGetterType方法是把传参的数据先解析出来,比如入参为嵌套的那种模式name=richType.richList[0],这个使用我们先通过PropertyTokenizer把是在richType类下的richList解析出来,然后通过reflector加载richType类,得到对应属性获取值大的方法MethodInvoker或者GetFieldInvoker,然后调用获取到属性值。

如果大家还是对这块有点疑问,可以直接调试下代码,会更加有助于理解。因为这块涉及到递归调用,口述方式我可能讲的会不太明白。

3. 今日总结

今天我们讲了关于TypeParameterResolver静态辅助类,MetaClass类元信息获取类的源码,希望大家能有收货~~

上一篇 下一篇

猜你喜欢

热点阅读