mybatis底层组件介绍-Reflector和ReflectorFactory

本文深入剖析MyBatis中的反射工具,详细解读Reflector类如何封装Java反射,实现属性与getter/setter方法间的高效映射。涵盖默认构造函数解析、getter与setter处理、属性冲突解决方案及字段遍历等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mybatis中的反射工具

mybatis对java中的反射进一步封装,使其更加易用。
首先看一下Reflector的类注释

This class represents a cached set of class definition information that
allows for easy mapping between property names and getter/setter methods.

主要包含了类的定义信息,能够快速地在属性和getter setter方法之间进行映射

构造函数

每个Reflector都对应一个类,并且带有这个类的setter和getter信息

// 当前解析的类
private final Class<?> type;
// 当前类中的可读属性
private final String[] readablePropertyNames;
// 当前类中的可写属性
private final String[] writablePropertyNames;
// setter名称和对应的Invoker
private final Map<String, Invoker> setMethods = new HashMap<>();
// getter名称和对应的Invoker
private final Map<String, Invoker> getMethods = new HashMap<>();
// 属性名称和对应的setter的入参参数类型
private final Map<String, Class<?>> setTypes = new HashMap<>();
// 属性名称和对应的getter的返回值类型
private final Map<String, Class<?>> getTypes = new HashMap<>();
// 默认构造函数
private Constructor<?> defaultConstructor;
// 大写的属性名称和真实名称之间的映射
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

初始化

还是看一下官方给的测试用例

@Test
void testGetSetterType() {
  ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
  Reflector reflector = reflectorFactory.findForClass(Section.class);
  Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
}
@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);
  }
}
```
从这里可以看出
其中reflectorMap的类型是
其中key是类的名称,value是对应该类的解析之后的reflect对象
```java
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
```
下面大量使用了java的反射
```java
public Reflector(Class<?> clazz) {
  type = clazz;
  addDefaultConstructor(clazz);
  addGetMethods(clazz);
  addSetMethods(clazz);
  addFields(clazz);
  readablePropertyNames = getMethods.keySet().toArray(new String[0]);
  writablePropertyNames = setMethods.keySet().toArray(new String[0]);
  for (String propName : readablePropertyNames) {
    caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  }
  for (String propName : writablePropertyNames) {
    caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  }
}
```

### 解析默认构造函数

```java
private void addDefaultConstructor(Class<?> clazz) {
  Constructor<?>[] constructors = clazz.getDeclaredConstructors();
  // 找到没有参数的构造函数,作为默认构造函数
  Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
    .findAny().ifPresent(constructor -> this.defaultConstructor = constructor);
}
```
### 解析getter
获取当前类的get方法信息
```java
private void addGetMethods(Class<?> clazz) {
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    // 获得当前类中的所有方法,包括继承来的和实现的接口方法
    Method[] methods = getClassMethods(clazz);
    /**
     * 从所有方法中筛选出get方法
     * 规则是使用PropertyNamer的isGetter方法来判断是否是get方法:方法没有参数并且方法的名称以get或者是is开头
     * 然后使用PropertyNamer通过方法名来确定对应的属性,因为get开头的方法和is开头的方法都会被认为是getter
     * 所以一个属性可能会对应多个method
     */
    Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
      .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
    // 解决一个属性对应多个getter的问题
    resolveGetterConflicts(conflictingGetters);
  }
```
#### 通过getter名称解析出属性的名称
```java
  public static String methodToProperty(String name) {
    if (name.startsWith("is")) {
      name = name.substring(2);
    } else if (name.startsWith("get") || name.startsWith("set")) {
      name = name.substring(3);
    } else {
      throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
    }

    // 这里会将属性名称的第一个字符转换成小写
    // 但是需要注意,如果第二字符也是大写的,那么不会将第一个字符转换成小写的,比如getUUID(),解析出来的属性名称就是UUID
    if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }
```
```java
private Method[] getClassMethods(Class<?> clazz) {
    Map<String, Method> uniqueMethods = new HashMap<>();
    Class<?> currentClass = clazz;
    // 从类的继承层次,从下往上找get方法
    while (currentClass != null && currentClass != Object.class) {
      // getDeclaredMethods获取由当前类声明的方法,不包括由父类声明的方法,包含实现的接口方法
      addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

      // we also need to look for interface methods -
      // because the class may be abstract
      // 将实现的接口的方法也添加进去
      Class<?>[] interfaces = currentClass.getInterfaces();
      for (Class<?> anInterface : interfaces) {
        addUniqueMethods(uniqueMethods, anInterface.getMethods());
      }
      // 移动到上一层
      currentClass = currentClass.getSuperclass();
    }

    Collection<Method> methods = uniqueMethods.values();

    return methods.toArray(new Method[0]);
  }

  private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
    for (Method currentMethod : methods) {
      if (!currentMethod.isBridge()) {
        String signature = getSignature(currentMethod);
        // check to see if the method is already known
        // if it is known, then an extended class must have
        // overridden a method
        // 当前方法并没有遍历过,添加到遍历集合中
        // 也就是说,如果遍历过,那么就不会添加,因为子类先遍历,所以保存的是子类的版本
        if (!uniqueMethods.containsKey(signature)) {
          uniqueMethods.put(signature, currentMethod);
        }
      }
    }
  }
```
这里看到了isBridge方法来判断方式是否是桥接方法,那么桥接方法是什么
```java
public class BridgeTest {
  public static class Father<T> {
    private T value;
    public void setValue(T value) {
      this.value = value;
    }
  }
  public static class Son extends Father<String> {
    @Override
    public void setValue(String value) {
      super.setValue(value);
    }
  }
  public static void main(String[] args) {
    // java中有类型擦除的概念,泛型在运行期间都是Object类型的
    Father father = new Son();
    father.setValue(new Object());
  }
}
```
执行上面的代码会报如下异常
```java
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
	at BridgeTest$Son.setValue(BridgeTest.java:13)
	at BridgeTest.main(BridgeTest.java:22)
```
实际上编译器会为Son自动生成一个如下的桥接方法
```java
public void setValue(Object object) {
	setValue((String)object)
}
```
#### 解决属性多个getter冲突
下面看一下如何解决一个属性名称对应多个方法
```java
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
    for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
      Method winner = null;
      String propName = entry.getKey();
      boolean isAmbiguous = false;
      // 遍历当前属性的冲突方法
      for (Method candidate : entry.getValue()) {
        if (winner == null) {
          winner = candidate;
          continue;
        }
        // 分别获得当前获胜方法的返回值类型和当前遍历到的方法的返回值类型
        Class<?> winnerType = winner.getReturnType();
        Class<?> candidateType = candidate.getReturnType();
        if (candidateType.equals(winnerType)) {
          // 返回类型相同,并且返回值类型不为boolean,那么标记为歧义
          if (!boolean.class.equals(candidateType)) {
            isAmbiguous = true;
            break;
          } else if (candidate.getName().startsWith("is")) {
            // 如果返回值类型是boolean,那么方法名以is开头的胜出
            winner = candidate;
          }
        } else if (candidateType.isAssignableFrom(winnerType)) {
          // 当前遍历到的方法的返回值是当前获胜者返回值类型的子类,获胜者不变
          // OK getter type is descendant
        } else if (winnerType.isAssignableFrom(candidateType)) {
          // 和上面的情况相反
          winner = candidate;
        } else {
          isAmbiguous = true;
          break;
        }
      }
      addGetMethod(propName, winner, isAmbiguous);
    }
  }
```
```java
private void addGetMethod(String name, Method method, boolean isAmbiguous) {
  // 根据现在是否存在歧义,创建两个不同的方法调用对象
  // 这里的getter如果冲突的话,那么创建的是AmbiguousMethodInvoker,该类对象在调用Invoke的时候会直接报错
  MethodInvoker invoker = isAmbiguous
      ? new AmbiguousMethodInvoker(method, MessageFormat.format(
          "Illegal overloaded getter method with ambiguous type for property ''{0}'' in class ''{1}''. This breaks the JavaBeans specification and can cause unpredictable results.",
          name, method.getDeclaringClass().getName()))
      : new MethodInvoker(method);
  // 建立属性和调用方法的映射
  getMethods.put(name, invoker);
  // 获得当前方法的返回值类型
  Type returnType = TypeParameterResolver.resolveReturnType(method, type);
  // 建立属性和返回值类型之间的映射
  getTypes.put(name, typeToClass(returnType));
}
```
下面看一下添加不具有对应getter和setter的属性的方法
### 解析属性
这里主要会遍历类的所有属性,然后判断当前通过setter解析后的属性集合中是否包含当前属性
如果不包含,那么会为这些属性生成getter和setter
```java
private void addFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      // 当前属性没有对应的setter
      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();
        // 当前属性不同时是static final的,为这个属性添加一个setter方法
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
          addSetField(field);
        }
      }
      // 当前属性没有getter,为这个属性添加一个getter
      if (!getMethods.containsKey(field.getName())) {
        addGetField(field);
      }
    }
    // 递归向上处理父类的属性
    if (clazz.getSuperclass() != null) {
      addFields(clazz.getSuperclass());
    }
  }
```
```java
private void addSetField(Field field) {
  if (isValidPropertyName(field.getName())) {
    setMethods.put(field.getName(), new SetFieldInvoker(field));
    Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
    setTypes.put(field.getName(), typeToClass(fieldType));
  }
}

private void addGetField(Field field) {
  if (isValidPropertyName(field.getName())) {
    getMethods.put(field.getName(), new GetFieldInvoker(field));
    Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
    getTypes.put(field.getName(), typeToClass(fieldType));
  }
}
```
刚才在看处理同一个属性对应多个setter或者getter的代码时会根据是否有歧义,生成不同类型的方法调用对象
当有歧义发生时,会创建AmbiguousMethodInvoker,调用invoke的时候直接抛异常
```java
public class AmbiguousMethodInvoker extends MethodInvoker {
  private final String exceptionMessage;

  public AmbiguousMethodInvoker(Method method, String exceptionMessage) {
    super(method);
    this.exceptionMessage = exceptionMessage;
  }

  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
    throw new ReflectionException(exceptionMessage);
  }
}
```
未产生歧义时创建的方法调用,使用类自身带有的method,调用时也是调用的该自有的method
```java
public class MethodInvoker implements Invoker {

  private final Class<?> type;
  private final Method method;

  public MethodInvoker(Method method) {
    this.method = method;
    if (method.getParameterTypes().length == 1) {
      type = method.getParameterTypes()[0];
    } else {
      type = method.getReturnType();
    }
  }

  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
    try {
      return method.invoke(target, args);
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        method.setAccessible(true);
        return method.invoke(target, args);
      } else {
        throw e;
      }
    }
  }

  @Override
  public Class<?> getType() {
    return type;
  }
}

```
再看下为没有setter的属性自动生成的setter
```java
public class SetFieldInvoker implements Invoker {
  private final Field field;

  public SetFieldInvoker(Field field) {
    this.field = field;
  }

  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException {
    try {
      field.set(target, args[0]);
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        field.setAccessible(true);
        field.set(target, args[0]);
      } else {
        throw e;
      }
    }
    return null;
  }

  @Override
  public Class<?> getType() {
    return field.getType();
  }
}
```
## ReflectFactory
ReflectFactory主要是为了缓存对应每个类的Reflector对象,避免频繁地解析
```java
public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  private final ConcurrentMap<Class<?>, 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) {
  	// 开启缓存,直接从map中获取
    if (classCacheEnabled) {
      // synchronized (type) removed see issue #461
      return reflectorMap.computeIfAbsent(type, Reflector::new);
    } else {
      return new Reflector(type);
    }
  }

}
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值