文章目录

mybatis解析xml时完成参数对象或者结果集对象等初始化,在执行流程中又要去动态修改这些对象的属性,所以单独设计了一套反射工具包,这些类封装在reflection包中,mybatis处理SQL参数或者结果集的时候几乎都有反射包的身影,这些主要类之间的依赖关系如下:

以SystemMetaObject.forObject(Object object)为入口,获取到MetaObject,以后目标对象的get、set方法都在MetaObject中执行了。
以正常的javabean对象为例子分析,执行MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);方法判断object对象,是集合类型还是Javabean类型,如果是Javabean类型,就实例化BeanWrapper等对象,主要类之间的依赖关系如图所示,大概描述下这几个类的作用:
MetaObject:根据目标对象类型,实例化不同的ObjectWrapper,还可以处理如XX.xx传入这种属性名的处理,以后调用get、set方法都用这个类,XX.xx属性内部代码实现:

public void setValue(String name, Object value) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
       //处理XX.xx属性,先判断XX是什么类型的ObjectWrapper,如果是对象就返回SystemMetaObject.NULL_META_OBJECT,Map返回MapWrapper,List返回ObjectWrapper
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        if (value == null && prop.getChildren() != null) {
          // don't instantiate child path if value is null
          return;
        } else {
            //XX类的set方法设置,并返回这个类的MetaValue(用于子属性的设置set方法设置)
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }
      metaValue.setValue(prop.getChildren(), value);
    } else {
      objectWrapper.set(prop, value);
    }
}

BeanWrapper:符合Javabean规范对象的封装类,通过MetaClass获取到Invoker对象,再调用method.invoke()方法执行原对象的内部方法.

PropertyTokenizer:属性分割解析器,可以处理多种参数写法,如:richType.richField、richMap.key、richMap[key](Map类型属性)、richType.richMap[key]、richList[0](List类型属性)、richType.richList[0]

DefaultObjectFactory:通过反射实例化类,可以修改构造函数的访问权限

MetaClass:通过传入目标对象的Class对象,Reflector对属性进行一些操作封装

Reflector:真正对接JDK接口实现反射的工具类,目标对象初始化时就把所有的get,set方法装进map,如果属性没有get\set方法,反射原理设置get/set方法,并把方法保存到map中,具体代码实现:

private void addFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      if (canAccessPrivateMethods()) {
        try {
          field.setAccessible(true);
        } catch (Exception e) {
          // Ignored. This is only a final precaution, nothing we can do.
        }
      }
      if (field.isAccessible()) {
        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());
    }
}

初始化时,先修改field的访问权限,field.setAccessible(true);即使是private也可以动态修改。所以结果集中的属性即使没有get/set方法,也可以赋值和取值。

GetFieldInvokerSetFieldInvoker分别动态设置属性的get、set方法
MethodInvoker执行目标函数的方法

文章目录