1.概述
Java 中的反射虽然功能强大,但对大多数开发人员来说,写出高质量的反射代码还是 有一定难度的。MyBatis 中专门提供了反射模块,该模块对 Java 原生的反射进行了良好的封装,提了更加简洁易用的 API,方便上层使调用,并且对反射操作进行了一系列优化,例如缓存了类的元数据,提高了反射操作的性能。
2. Reflector
org.apache.ibatis.reflection.Reflector ,反射器,每个 Reflector 对应一个类。Reflector 会缓存反射操作需要的类的信息,例如:构造方法、属性名、setting / getting 方法等等。代码如下:
public class Reflector {
/**
* 对应的类
*/
private final Class<?> type;
/**
* 可读属性数组
*/
private final String[] readablePropertyNames;
/**
* 可写属性集合
*/
private final String[] writeablePropertyNames;
/**
* 属性对应的 setting 方法的映射。
*
* key 为属性名称
* value 为 Invoker 对象
*/
private final Map<String, Invoker> setMethods = new HashMap<>();
/**
* 属性对应的 getting 方法的映射。
*
* key 为属性名称
* value 为 Invoker 对象
*/
private final Map<String, Invoker> getMethods = new HashMap<>();
/**
* 属性对应的 setting 方法的方法参数类型的映射。{@link #setMethods}
*
* key 为属性名称
* value 为方法参数类型
*/
private final Map<String, Class<?>> setTypes = new HashMap<>();
/**
* 属性对应的 getting 方法的返回值类型的映射。{@link #getMethods}
*
* key 为属性名称
* value 为返回值的类型
*/
private final Map<String, Class<?>> getTypes = new HashMap<>();
/**
* 默认构造方法
*/
private Constructor<?> defaultConstructor;
/**
* 不区分大小写的属性集合
*/
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
public Reflector(Class<?> clazz) {
// 设置对应的类
type = clazz;
// <1> 初始化 defaultConstructor
addDefaultConstructor(clazz);
// <2> // 初始化 getMethods 和 getTypes ,通过遍历 getting 方法
addGetMethods(clazz);
// <3> // 初始化 setMethods 和 setTypes ,通过遍历 setting 方法。
addSetMethods(clazz);
// <4> // 初始化 getMethods + getTypes 和 setMethods + setTypes ,通过遍历 fields 属性。
addFields(clazz);
// <5> 初始化 readablePropertyNames、writeablePropertyNames、caseInsensitivePropertyMap 属性
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
// ... 省略一些方法
}
2.1 addDefaultConstructor
addDefaultConstructor(Class<?> clazz) 方法,查找默认无参构造方法。
private void addDefaultConstructor(Class<?> clazz) {
// 获得所有构造方法
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
.findAny().ifPresent(constructor -> this.defaultConstructor = constructor);
}
2.2 addGetMethods
addGetMethods(Class<?> cls) 方法,初始化 getMethods 和 getTypes ,通过遍历 getting 方法
private void addGetMethods(Class<?> clazz) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
//获得所有方法
Method[] methods = getClassMethods(clazz);
//过滤获得get 方法
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
resolveGetterConflicts(conflictingGetters);
}
2.2.1 getClassMethods
#getClassMethods(Class<?> cls) 方法,获得所有方法。代码如下:
Map<String, Method> uniqueMethods = new HashMap<>();
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
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]);