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

MyBatis印象阅读之反射工具Reflector

作者: 向光奔跑_ | 来源:发表于2019-07-23 19:34 被阅读0次

技术债

  • ReflectorFactory
  • Configuration
  • TypeAliasRegistry
  • TypeHandlerRegistry

今天我们来偿还关于反射工具的技术债,也就是对应上述的ReflectorFactory类。

首先我们需要思考下面一个问题:
如果是让你搭建一个类反射的工具类,你会如何设计呢?

1.1MyBatis框架下的反射机制

首先我们查阅MyBatis框架下源码,可以很容易发现有一个包和反射有关,如下:


MyBatis反射包

乍一看,可能大家会被这么多类给吓到,感觉心虚,但是不要慌,你与他人的差距恰恰是在这里。(给自己喝一口鸡汤)

心定之后便是来思考从哪个类来入手(切记不要像个无头苍蝇下乱撞,顺着思路看会顺利很多)。这时我就瞄向了测试类,也就是官方单元测试Demo来整理思路。


反射测试类

那我们便开始进行分析.

2.DefaultObjectFactoryTest类抛砖引玉

//DefaultObjectFactoryTest


  @Test
  void createClass() {
    DefaultObjectFactory defaultObjectFactory = new DefaultObjectFactory();
    TestClass testClass = defaultObjectFactory.create(TestClass.class,
        Arrays.asList(String.class, Integer.class), Arrays.asList("foo", 0));

    Assertions.assertEquals((Integer) 0, testClass.myInteger, "myInteger didn't match expected");
    Assertions.assertEquals("foo", testClass.myString, "myString didn't match expected");
  }

其中这里涉及到的TestClass为:

public class TestClass {
  String myString;
  Integer myInteger;

  public TestClass(String myString, Integer myInteger) {
    this.myString = myString;
    this.myInteger = myInteger;
  }
}

万事俱备只欠东风,我们进行分析。

2.1 DefaultObjectFactory解析

这个类没有属性,默认无参构造方法。我们直接来看上面调用的方法:

 //DefaultObjectFactory
  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    Class<?> classToCreate = resolveInterface(type);
    // we know types are assignable
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }

 /**
  * 解析类的类型
  */
    protected Class<?> resolveInterface(Class<?> type) {
    Class<?> classToCreate;
    if (type == List.class || type == Collection.class || type == Iterable.class) {
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      classToCreate = HashMap.class;
    } else if (type == SortedSet.class) { // issue #510 Collections Support
      classToCreate = TreeSet.class;
    } else if (type == Set.class) {
      classToCreate = HashSet.class;
    } else {
      classToCreate = type;
    }
    return classToCreate;
    }
  
    /**
   * 实例化类
   */
  private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    //如无构造函数和参数传进来,使用默认无参构造方法
    try {
      Constructor<T> constructor;
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        try {
          return constructor.newInstance();
        } catch (IllegalAccessException e) {
          if (Reflector.canControlMemberAccessible()) {
            constructor.setAccessible(true);
            return constructor.newInstance();
          } else {
            throw e;
          }
        }
      }
      //如存在构造函数和参数传进来,匹配有参构造方法实例化
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      try {
        return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
        } else {
          throw e;
        }
      }
    } catch (Exception e) {
      String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
          .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
      String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
          .stream().map(String::valueOf).collect(Collectors.joining(","));
      throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }

这个类逻辑不复杂,总结两点:

  • 遇到无参构造函数使用java反射实例情况
  • 遇到有参构造函数使用java反射实例情况

下面来挑战下一个测试类ReflectorTest。

2.2 ReflectorTest类解析

由于这个类是其他类的基础,我们变先拿这个类开刀,顾名思义这个类和Reflector有关,那么接下来我们开始撸第一个方法:

  @Test
  void testGetSetterType() {
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
  }

我们来看 reflectorFactory.findForClass方法:

  //DefaultReflectorFactory
  @Override
  public Reflector findForClass(Class<?> type) {
    if (classCacheEnabled) {
      // synchronized (type) removed see issue #461
      return reflectorMap.computeIfAbsent(type, Reflector::new);
    } else {
      return new Reflector(type);
    }
  }

如果缓存中存在则从缓存中取,如果没有直接通过new创建一个Reflector实例,那么接下来重点便是Reflector。

2.2.1 Reflector类解析

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

//Reflector

  private final Class<?> type;
  private final String[] readablePropertyNames;
  private final String[] writablePropertyNames;
  private final Map<String, Invoker> setMethods = new HashMap<>();
  private final Map<String, Invoker> getMethods = new HashMap<>();
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  private Constructor<?> defaultConstructor;

  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();


public Reflector(Class<?> clazz) {
    //这里可以理解一个类一个Reflector实例
    type = clazz;
    //添加默认构造函数,即无参构造函数
    addDefaultConstructor(clazz);
    //添加get或者is开头的方法名的方法
    addGetMethods(clazz);
    //添加set开头的方法名的方法
    addSetMethods(clazz);
    //添加属性
    addFields(clazz);
    //可读属性,也就是存在Get方法的属性
    readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
    //可写属性,也就是存在Set方法的属性
    writablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
    //下面就是把两个方法转化为可读属性和可写属性的大写,并使用Map类型映射
    for (String propName : readablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }

这个类方法有点多,我们只是大概看下类,见名知意即可:


Reflector类方法

Reflector构造方法中类的很简单,结合我的注释,我们来看下代码:

/**
   * 添加默认构造函数,即无参构造函数
   */
  private void addDefaultConstructor(Class<?> clazz) {
    Constructor<?>[] consts = clazz.getDeclaredConstructors();
    for (Constructor<?> constructor : consts) {
      if (constructor.getParameterTypes().length == 0) {
        this.defaultConstructor = constructor;
      }
    }
  }

 /**
   * 添加get或者is开头的方法名的方法
   */
  private void addGetMethods(Class<?> cls) {
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    Method[] methods = getClassMethods(cls);
    for (Method method : methods) {
      if (method.getParameterTypes().length > 0) {
        continue;
      }
      String name = method.getName();
      if ((name.startsWith("get") && name.length() > 3)
          || (name.startsWith("is") && name.length() > 2)) {
        name = PropertyNamer.methodToProperty(name);
        addMethodConflict(conflictingGetters, name, method);
      }
    }
    resolveGetterConflicts(conflictingGetters);
  }

 /**
   * 添加set开头的方法名的方法
   */
  private void addSetMethods(Class<?> cls) {
    Map<String, List<Method>> conflictingSetters = new HashMap<>();
    Method[] methods = getClassMethods(cls);
    for (Method method : methods) {
      String name = method.getName();
      if (name.startsWith("set") && name.length() > 3) {
        if (method.getParameterTypes().length == 1) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingSetters, name, method);
        }
      }
    }
    resolveSetterConflicts(conflictingSetters);
  }

  /**
   * 添加属性
   * @param clazz
   */
  private void addFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      if (!setMethods.containsKey(field.getName())) {
        // issue #379 - removed the check for final because JDK 1.5 allows
        // modification of final fields through reflection (JSR-133). (JGB)
        // pr #16 - final static can only be set by the classloader
        int modifiers = field.getModifiers();
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
          addSetField(field);
        }
      }
      if (!getMethods.containsKey(field.getName())) {
        addGetField(field);
      }
    }
    if (clazz.getSuperclass() != null) {
      addFields(clazz.getSuperclass());
    }
  }

剩下的就不一一列举,总结一下:
Reflector就是处理构造函数中传入的class,然后解析出其所有属性,包括构造函数,set、get方法还有所有对应的属性。我们至少要记住这个类的作用,对于后面解析很有作用。

3.今日总结

今天我们主要分析了ReflectorFactory,知其意是用来解析某个类属性的。那我们还剩下:

技术债

  • Configuration
  • TypeAliasRegistry
  • TypeHandlerRegistry

相关文章

网友评论

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

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