美文网首页
MyBatis印象阅读之反射工具扩展

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

作者: 向光奔跑_ | 来源:发表于2019-07-24 11:33 被阅读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类元信息获取类的源码,希望大家能有收货~~

    相关文章

      网友评论

          本文标题:MyBatis印象阅读之反射工具扩展

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