(四)MyBatis源码阅读: MyBatis基础模块-反射模块

一、概述

  MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错,为了简化反射操作的相关代码,MyBatis提供了专门的反射模块,该模块位于org.apache.ibatis.reflection包下,它对常见的反射操作做了进一步的封装,提供了更加简洁方便的反射API。

(四)MyBatis源码阅读: MyBatis基础模块-反射模块_第1张图片

 

(四)MyBatis源码阅读: MyBatis基础模块-反射模块_第2张图片

 

二、反射模块

(一)Reflector

1、属性

首先来看下Reflector中提供的相关属性的含义

  // 对应的Class 类型 
  private final Class type;
  // 可读属性的名称集合 可读属性就是存在 getter方法的属性,初始值为null
  private final String[] readablePropertyNames;
  // 可写属性的名称集合 可写属性就是存在 setter方法的属性,初始值为null
  private final String[] writablePropertyNames;
  // 记录了属性相应的setter方法,key是属性名称,value是Invoker方法
  // 他是对setter方法对应Method对象的封装
  private final Map setMethods = new HashMap<>();
  // 属性相应的getter方法
  private final Map getMethods = new HashMap<>();
  // 记录了相应setter方法的参数类型,key是属性名称 value是setter方法的参数类型
  private final Map> setTypes = new HashMap<>();
  // 和上面的对应
  private final Map> getTypes = new HashMap<>();
  // 记录了默认的构造方法
  private Constructor defaultConstructor;

  // 记录了所有属性名称的集合
  private Map caseInsensitivePropertyMap = new HashMap<>();

2、构造方法

在Reflector的构造器中会完成相关的属性的初始化操作

  // 解析指定的Class类型 并填充上述的集合信息
  public Reflector(Class clazz) {
    type = clazz; // 初始化 type字段
    addDefaultConstructor(clazz);// 设置默认的构造方法
    addGetMethods(clazz);// 获取getter方法
    addSetMethods(clazz); // 获取setter方法
    addFields(clazz); // 处理没有getter/setter方法的字段
    // 初始化 可读属性名称集合
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    // 初始化 可写属性名称集合
    writablePropertyNames = setMethods.keySet().toArray(new String[0]);
    // caseInsensitivePropertyMap记录了所有的可读和可写属性的名称 也就是记录了所有的属性名称
    for (String propName : readablePropertyNames) {
      // 属性名称转大写
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writablePropertyNames) {
      // 属性名称转大写
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }

(二)ReflectorFactory

ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。接口的定义如下:

public interface ReflectorFactory {
  // 检测该ReflectorFactory是否缓存了Reflector对象
  boolean isClassCacheEnabled();
  // 设置是否缓存Reflector对象
  void setClassCacheEnabled(boolean classCacheEnabled);
  // 创建指定了Class的Reflector对象
  Reflector findForClass(Class type);
}

然后我们来看看它的具体实现

1、DefaultReflectorFactory

MyBatis只为该接口提供了DefaultReflectorFactory这一个实现类。他与Reflector的关系如下:

(四)MyBatis源码阅读: MyBatis基础模块-反射模块_第3张图片

DefaultReflectorFactory中的实现,代码比较简单,我们直接贴出来

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  // 实现对 Reflector 对象的缓存
  private final ConcurrentMap, Reflector> reflectorMap = new ConcurrentHashMap<>();

  public DefaultReflectorFactory() {
  }

  @Override
  public boolean isClassCacheEnabled() {
    return classCacheEnabled;
  }

  @Override
  public void setClassCacheEnabled(boolean classCacheEnabled) {
    this.classCacheEnabled = classCacheEnabled;
  }

  @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);
    }
  }
}

 

(三)Invoker

针对于Class中Field和Method的调用,在MyBatis中封装了Invoker对象来统一处理(有使用到适配器模式)

/**
 * @author Clinton Begin
 */
public interface Invoker {
  // 执行Field或者Method
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

  // 返回属性相应的类型
  Class getType();
}

该接口有对应的三个实现

(四)MyBatis源码阅读: MyBatis基础模块-反射模块_第4张图片

 

(四)MetaClass

在Reflector中可以针对普通的属性操作,但是如果出现了比较复杂的属性,比如 private Person person; 这种,我们要查找的表达式 person.userName.针对这种表达式的处理,这时就可以通过MetaClass来处理了。我们来看看主要的属性和构造方法。

/**
 * 通过 Reflector 和 ReflectorFactory 的组合使用 实现对复杂的属性表达式的解析
 * @author Clinton Begin
 */
public class MetaClass {
  // 缓存 Reflector
  private final ReflectorFactory reflectorFactory;
  // 创建 MetaClass时 会指定一个Class reflector会记录该类的相关信息
  private final Reflector reflector;

  private MetaClass(Class type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type);
  }
  // ....
}

(五)MetaObject

我们可以通过MetaObject对象解析复杂的表达式来对提供的对象进行操作。具体的通过案例来演示会更直观些


    @Test
    public void shouldGetAndSetField() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richField", "foo");
        System.out.println(meta.getValue("richField"));
    }

    @Test
    public void shouldGetAndSetNestedField() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richType.richField", "foo");
        System.out.println(meta.getValue("richType.richField"));
    }

    @Test
    public void shouldGetAndSetMapPairUsingArraySyntax() {
        RichType rich = new RichType();
        MetaObject meta = SystemMetaObject.forObject(rich);
        meta.setValue("richMap[key]", "foo");
        System.out.println(meta.getValue("richMap[key]"));
    }

以上三个方法的输出结果都是foo

三、反射模块的应用

(一)SqlSessionFactory

在创建SqlSessionFactory操作的时候会完成Configuration对象的创建,而在Configuration中默认定义的ReflectorFactory的实现就是DefaultReflectorFactory对象。然后在解析全局配置文件的代码中,给用户提供了ReflectorFactory的扩展,也就是我们在全局配置文件中可以通reflectorFactory标签来使用我们自定义的ReflectorFactory。

(四)MyBatis源码阅读: MyBatis基础模块-反射模块_第5张图片

 (二)执行SQL

在Statement获取结果集后,在做结果集映射的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。

  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result 标识是否使用 构造函数创建对象
    // 记录构造函数的参数类型
    final List> constructorArgTypes = new ArrayList<>();
    // 记录构造函数的实参
    final List constructorArgs = new ArrayList<>();
    // 创建该行记录对应的结果对象,核心步骤
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      final List propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // 如果有嵌套查询且配置了延迟加载,则创建代理对象
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
  }

然后在DefaultResultSetHandler的getRowValue方法中在做自动映射的时候

private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix, Object partialObject) throws SQLException {
    final String resultMapId = resultMap.getId();
    Object rowValue = partialObject;
    if (rowValue != null) {
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      putAncestor(rowValue, resultMapId);
      applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
      ancestorObjects.remove(resultMapId);
    } else {
      final ResultLoaderMap lazyLoader = new ResultLoaderMap();
      rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
      if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        final MetaObject metaObject = configuration.newMetaObject(rowValue);
        boolean foundValues = this.useConstructorMappings;
        if (shouldApplyAutomaticMappings(resultMap, true)) {
          foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
        }
        foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
        putAncestor(rowValue, resultMapId);
        foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true) || foundValues;
        ancestorObjects.remove(resultMapId);
        foundValues = lazyLoader.size() > 0 || foundValues;
        rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
      }
      if (combinedKey != CacheKey.NULL_CACHE_KEY) {
        nestedResultObjects.put(combinedKey, rowValue);
      }
    }
    return rowValue;
  }

继续跟踪,在createAutomaticMappings方法中

  private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
    // 获取ResultSet中存在,但在ResultMap中没有明确映射的列
    List autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
    boolean foundValues = false;
    if (!autoMapping.isEmpty()) {
      for (UnMappedColumnAutoMapping mapping : autoMapping) {
        // 使用TypeHandler 获取自定映射的列值
        final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
        if (value != null) {
          foundValues = true;
        }
        if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
          // gcode issue #377, call setter on nulls (value is not 'found')
          // 将自动映射的属性值设置到结果对象中
          metaObject.setValue(mapping.property, value);
        }
      }
    }
    return foundValues;
  }

你可能感兴趣的:(Mybatis,mybatis,java,mysql)