聊聊mybatis的反射之Reflector类

454 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

聊聊mybatis的反射之Reflector类

反射是一块重要的内容,java中的反射让我们在程序运行的时候可以获取到java对象的属性和方法,mybatis有自己的反射工具箱模块,下面我就简单说一下mybatis 反射工具箱的一些类和方法

Reflector类是反射器,通过给出的测试类ReflectorTest我们可以知道这个类的具体用法:

@Test
  public void testGetSetterType() throws Exception {
    Reflector reflector = Reflector.forClass(Section.class);
    Assert.assertEquals(Long.class, reflector.getSetterType("id"));
  }

通过Reflector的构造器,我们也能知道,只需要传入Class对象,Reflector就能解析这个Class对象,并把Class类的信息分类填充到Reflector类自定的一些成员变量中

private Reflector(Class<?> clazz) {
    type = clazz;
    //加入构造函数
    addDefaultConstructor(clazz);
    //加入getter
    addGetMethods(clazz);
    //加入setter
    addSetMethods(clazz);
    //加入字段
    addFields(clazz);
    readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
    writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
    for (String propName : readablePropertyNames) {
        //这里为了能找到某一个属性,就把他变成大写作为map的key。。。
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writeablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }
  1. ,type记录class的类型
  2. addDefaultConstructor是通过反射得到Class的无参构造方法
  3. addGetMethods()方法就是用来读取Class的getter方法,然后放入getMethods集合中和getTypes集合中,
  4. addSetMethods()方法就是读取Class文件的setter方法,放入setMethods方法列表集合和setTypes类型列表集合中
  5. addFields()方法是针对class中没有getter setter方法的字段生成GetFieldInvoker类来放入getMethods、getTypes、setMethods和setTypes集合中
  6. 然后初始化readablePropertyNames和writeablePropertyNames,readablePropertyNames是getter的属性列表集合,writeablePropertyNames是setter的属性列表集合
  7. 把readablePropertyNames和writeablePropertyNames中全部转为大写,保存到caseInsensitivePropertyMap中,key是属性名的大写,value是属性名

步骤三中我们提到addGetMethods()方法就是用来读取Class的getter方法,然后放入getMethods集合中和getTypes集合中,具体是怎么做的呢?看一下源码:

private void addGetMethods(Class<?> cls) {
    Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
    //这里getter和setter都调用了getClassMethods,有点浪费效率了。不妨把addGetMethods,addSetMethods合并成一个方法叫addMethods
    Method[] methods = getClassMethods(cls);
    for (Method method : methods) {
      String name = method.getName();
      if (name.startsWith("get") && name.length() > 3) {
        if (method.getParameterTypes().length == 0) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingGetters, name, method);
        }
      } else if (name.startsWith("is") && name.length() > 2) {
        if (method.getParameterTypes().length == 0) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingGetters, name, method);
        }
      }
    }
    resolveGetterConflicts(conflictingGetters);
  }
  1. 调用getClassMethods(cls);获取方法信息,点进去这个方法可以看到定义了一个map集合Map<String, Method> uniqueMethods = new HashMap<String, Method>(); 它的key是返回值类型#方法名称:参数类型:参数类型。。。,value是Method对象,key保证全局唯一,使用map能进行去重
  2. 获取到这些methods对象后,循环遍历,找出getter方法来,放入conflictingGetters集合中,key是属性名。value是对应的getter方法的集合,为什么是集合呢,因为有可能存在方法的重写
  3. 最后resolveGetterConflicts()方法解决签名的冲突,就是比较getter方法的返回值,取子类的getter方法,在这个方法里调用addGetMethod把对应的Method生成MethodInvoker对象保存到getMethods中

总结

今天主要介绍了一下mybatis反射模块的Reflector类的构造方法的一些细节和用到成员变量,希望mybatis源码的分析能对你有所帮助。