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

ReflectorFactory
创建 Reflector 对象,工厂模式接口
public interface ReflectorFactory {
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean classCacheEnabled);
Reflector findForClass(Class<?> type);
}
DefaultReflectorFactory
反射工厂,用于生产 Reflector 对象,并缓存Reflector 对象
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) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
// If the specified key is not already associated with a value,
// attempts to compute its value using the given mapping function
// and enters it into this map unless {@code null}.
// absent 缺席的;如果type值不存在,就应用后面的函数,计算出来,计算结果非空,放入map中;并返回计算值;
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
Reflector
Reflector 是 MyBatis 中反射模块的基础,每个 Reflector 对象都对应一个类,在 Reflector 中缓存了反射操作需要使用的类的元信息,包含原始类、类的构造方法、 写字段、读字段、getter 方法、setter 方法 、方法的返回类型。
public class Reflector {
private final Class<?> type; //类名称 Section
private final String[] readablePropertyNames; //可读的类属性 id
private final String[] writablePropertyNames; //可写的类属性 id
// Invoker 是一个封装了一个类的 GetField、SetFiled、getter 和 setter 方法 的对象,供后面反射调用类的字段、getter、setter 方法,方便使用
private final Map<String, Invoker> setMethods = new HashMap<>(); //<属性,set方法> id,setId
private final Map<String, Invoker> getMethods = new HashMap<>();
private final Map<String, Class<?>> setTypes = new HashMap<>();
private final Map<String, Class<?>> getTypes = new HashMap<>(); //<属性,get方法> id,java.lang.Long
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>(); //元素为属性大小写不敏感的; ID :id
public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz); //赋值默认的构造函数
addGetMethods(clazz);
addSetMethods(clazz);
addFields(clazz); //处理没有getter、setter方法的字段
// Set.toArray(T[] a), a 这参数有两个作用,1.指定数组的类型,2.指定数组的大小;如果数组的大小为0,只采用这个数组的类型,大小根据 Set 集合元素的个数;a 数组的大小不为0:新数组大小为 a 这个数组指定的参数大小
/**
* 对于Set而言,它只知道它内部保存的是Object,所以默认情况下,toArray只能是返回一个由这些Object构成的Object数组出来。但程序的作者或许更清楚其内部元素的更具体的类型,因此,HashSet类提供了toArray的另一个重载版本,允许用户指定一种比Object[]更具体的数组类型,方法是传递一个用户想要的数组类型的一个数组实例进去,多长都无所谓(因此我们常常使用一个0长度的,毕竟把类型带进去就OK了),于是,toArray内部就会按照你想要的这种类型,给构造一个数组出来。这样构造出来的数组,当然是很安全地被调用者转换回那个实际的类型。
*/
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);
}
}
/**
* 添加默认的构造方法
* @param clazz
*/
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
// filter 过滤出满足表达式的元素
Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
.findAny().ifPresent(constructor -> this.defaultConstructor = constructor);
}
private void addGetMethods(Class<?> clazz) {//class org.apache.ibatis.reflection.ReflectorTest$Section
Map<String, List<Method>> conflictingGetters = new HashMap<>();
//4 methods
// public abstract java.lang.Object org.apache.ibatis.reflection.ReflectorTest$Entity.getId()
// public java.lang.Long org.apache.ibatis.reflection.ReflectorTest$AbstractEntity.getId()
// public void org.apache.ibatis.reflection.ReflectorTest$AbstractEntity.setId(java.lang.Long)
// public abstract void org.apache.ibatis.reflection.ReflectorTest$Entity.setId(java.lang.Object)
// 获取类的 getter 方法们
Method[] methods = getClassMethods(clazz);
// addMethodConflict() 是将一个类的一个属性,的多个 getter 方法,放入 conflictingGetters 集合中,key 是 属性名称,value 是 这个属性的所有的 getter 方法,包含父类继承的等 getter 方法。
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
//解决多个类、多个接口 的继承 和实现 之间的 多个getter方法 冲突;保留最小辈(下限)类的get方法
resolveGetterConflicts(conflictingGetters);
}
//解决多个类、多个接口 的继承 和实现 之间的 多个getter方法 冲突;保留最小辈(下限)类的get方法,
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; //模糊不清的;这个属性的方式 是否是 模糊不清楚的;如果一个类是模糊不清楚的;最终会抛出AmbiguousMethodInvoker
for (Method candidate : entry.getValue()) {
if (winner == null) {
winner = candidate;
continue;
}
Class<?> winnerType = winner.getReturnType();
Class<?> candidateType = candidate.getReturnType();
if (candidateType.equals(winnerType)) {
if (!boolean.class.equals(candidateType)) {
isAmbiguous = true;
break;
} else if (candidate.getName().startsWith("is")) {
winner = candidate;
}
// Object.isAssignableFrom(String.class) true --> string is assignable from object ; string 是被检查的类; object 是 string supper 类
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
} else if (winnerType.isAssignableFrom(candidateType)) {
winner = candidate;
} else {
isAmbiguous = true;
break;
}
}
// 类的属性,类的正确的 getter 方法,getter 方法 封装成 Invoker 对象,放入 getMethods 集合中,然后返回类型放入 getTypes 集合中
addGetMethod(propName, winner, isAmbiguous);
}
}
/**
* 将这个类的这个属性,这个属性的 getter 方法,封装成 MethodInvoker 对象,方便后面反射时,对属性的 getter 方法的操作,
* 如果 isAmbiguous 是 true,则会创建一个 AmbiguousMethodInvoker,来提示这个 getter 方法不确实,是不清楚的,方便后面报错
* @param name 类的属性名称
* @param method 类的属性,对应的 getter 方法
* @param isAmbiguous 这个属性的 getter 是否是确定的,是唯一的,不是模糊的
*/
private void addGetMethod(String name, Method method, boolean isAmbiguous) {
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);
// 查找 getter 方法的 返回数据类型
Type returnType = TypeParameterResolver.resolveReturnType(method, type);
// 放入 getTypes 集合中
getTypes.put(name, typeToClass(returnType));
}
private void addSetMethods(Class<?> clazz) {
Map<String, List<Method>> conflictingSetters = new HashMap<>();
Method[] methods = getClassMethods(clazz);
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 1 && PropertyNamer.isSetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingSetters, PropertyNamer.methodToProperty(m.getName()), m));
resolveSetterConflicts(conflictingSetters);
}
/**
* 处理一个类的属性的多个getter 或者 setter 方法;
* @param conflictingMethods key 是一个类的属性,value 是这个属性的所有的 getter 或者 setter 方法
* @param name
* @param method
*/
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
// 是否有效的属性值
if (isValidPropertyName(name)) {
List<Method> list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList<>());
list.add(method);
}
}
private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
for (String propName : conflictingSetters.keySet()) {
List<Method> setters = conflictingSetters.get(propName);
Class<?> getterType = getTypes.get(propName);
boolean isGetterAmbiguous = getMethods.get(propName) instanceof AmbiguousMethodInvoker;
boolean isSetterAmbiguous = false;
Method match = null;
for (Method setter : setters) {
if (!isGetterAmbiguous && setter.getParameterTypes()[0].equals(getterType)) {
// should be the best match
match = setter;
break;
}
if (!isSetterAmbiguous) {
match = pickBetterSetter(match, setter, propName);
isSetterAmbiguous = match == null;
}
}
if (match != null) {
addSetMethod(propName, match);
}
}
}
/**
* 冲突的 setter 方法,选择一个合适的 setter 方法返回
* @param setter1
* @param setter2
* @param property
* @return
*/
private Method pickBetterSetter(Method setter1, Method setter2, String property) {
if (setter1 == null) {
return setter2;
}
Class<?> paramType1 = setter1.getParameterTypes()[0];
Class<?> paramType2 = setter2.getParameterTypes()[0];
if (paramType1.isAssignableFrom(paramType2)) {
return setter2;
} else if (paramType2.isAssignableFrom(paramType1)) {
return setter1;
}
MethodInvoker invoker = new AmbiguousMethodInvoker(setter1,
MessageFormat.format(
"Ambiguous setters defined for property ''{0}'' in class ''{1}'' with types ''{2}'' and ''{3}''.",
property, setter2.getDeclaringClass().getName(), paramType1.getName(), paramType2.getName()));
setMethods.put(property, invoker);
Type[] paramTypes = TypeParameterResolver.resolveParamTypes(setter1, type);
setTypes.put(property, typeToClass(paramTypes[0]));
return null;
}
private void addSetMethod(String name, Method method) {
MethodInvoker invoker = new MethodInvoker(method);
setMethods.put(name, invoker);
Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);
setTypes.put(name, typeToClass(paramTypes[0]));
}
//将一个类型,转化为相应的class类
private Class<?> typeToClass(Type src) {
Class<?> result = null;
if (src instanceof Class) {
result = (Class<?>) src;
} else if (src instanceof ParameterizedType) {
result = (Class<?>) ((ParameterizedType) src).getRawType();
} else if (src instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) src).getGenericComponentType();
if (componentType instanceof Class) {
result = Array.newInstance((Class<?>) componentType, 0).getClass();
} else {
Class<?> componentClass = typeToClass(componentType);
result = Array.newInstance(componentClass, 0).getClass();
}
}
if (result == null) {
result = Object.class;
}
return result;
}
//一个递归的调用关系;处理类的field,方便反射调用,将这个字段的对应方法分别 添加到 setMethods、getMethods、setTypes、getTypes 这几个集合中,方便使用
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
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))) {
// 处理类的 set 字段和字段的返回类型
addSetField(field);
}
}
if (!getMethods.containsKey(field.getName())) {
// 处理类的 get 字段和字段的返回类型
addGetField(field);
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
/**
* 处理类的 set 字段和字段的返回类型
* @param field
*/
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));
}
}
/**
* 处理类的 get 字段和字段的返回类型
* @param field
*/
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));
}
}
//是否有效的属性值
private boolean isValidPropertyName(String name) {
return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
}
/**
* 获取类的所有的 getter 方法
* 获取类的所有的 getter 方法
* This method returns an array containing all methods
* declared in this class and any superclass.
* We use this method, instead of the simpler <code>Class.getMethods()</code>,
* because we want to look for private methods as well.
*
* @param clazz The class
* @return An array containing all methods in this class
*/
private Method[] getClassMethods(Class<?> clazz) {
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]);
}
/**
* 解决 getter 方法的唯一性
* @param uniqueMethods
* @param methods
*/
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);
}
}
}
}
/**
* getter 方法的签名,确定方法的唯一性
* 签名:返回值类型#方法名称:参数类型列表
* @param method
* @return
*/
private String getSignature(Method method) {
StringBuilder sb = new StringBuilder();
Class<?> returnType = method.getReturnType();
if (returnType != null) {
sb.append(returnType.getName()).append('#');
}
sb.append(method.getName());
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
sb.append(i == 0 ? ':' : ',').append(parameters[i].getName());
}
return sb.toString();
}
/**
* 检测成员的访问权限
* Checks whether can control member accessible.
*
* @return If can control member accessible, it return {@literal true}
* @since 3.5.0
*/
public static boolean canControlMemberAccessible() {
try {
SecurityManager securityManager = System.getSecurityManager();
if (null != securityManager) {
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
} catch (SecurityException e) {
return false;
}
return true;
}
/**
* Gets the name of the class the instance provides information for.
*
* @return The class name
*/
public Class<?> getType() {
return type;
}
public Constructor<?> getDefaultConstructor() {
if (defaultConstructor != null) {
return defaultConstructor;
} else {
throw new ReflectionException("There is no default constructor for " + type);
}
}
public boolean hasDefaultConstructor() {
return defaultConstructor != null;
}
public Invoker getSetInvoker(String propertyName) {
Invoker method = setMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}
public Invoker getGetInvoker(String propertyName) {
Invoker method = getMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}
/**
* Gets the type for a property setter.
* 获取一个属性的,一个setter()方法的属性类型
*
* @param propertyName - the name of the property
* @return The Class of the property setter
*/
public Class<?> getSetterType(String propertyName) {
Class<?> clazz = setTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
}
return clazz;
}
/**
* Gets the type for a property getter.
*
* @param propertyName - the name of the property
* @return The Class of the property getter
*/
public Class<?> getGetterType(String propertyName) {
Class<?> clazz = getTypes.get(propertyName);
if (clazz == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return clazz;
}
/**
* Gets an array of the readable properties for an object.
*
* @return The array
*/
public String[] getGetablePropertyNames() {
return readablePropertyNames;
}
/**
* Gets an array of the writable properties for an object.
*
* @return The array
*/
public String[] getSetablePropertyNames() {
return writablePropertyNames;
}
/**
* Check to see if a class has a writable property by name.
*
* @param propertyName - the name of the property to check
* @return True if the object has a writable property by the name
*/
public boolean hasSetter(String propertyName) {
return setMethods.keySet().contains(propertyName);
}
/**
* Check to see if a class has a readable property by name.
*
* @param propertyName - the name of the property to check
* @return True if the object has a readable property by the name
*/
public boolean hasGetter(String propertyName) {
return getMethods.keySet().contains(propertyName);
}
public String findPropertyName(String name) {
return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
}
}
Invoker
Invoker 调用者、是对象 getter 或者 setter 方法、get一个字段、set 一个字段,这几种类方法和属性的封装,方便放射对象调用。
UML

public interface Invoker {
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
Class<?> getType();
}
GetFieldInvoker
类字段 get 方法的封装
public class GetFieldInvoker implements Invoker {
// get 一个类的字段
private final Field field;
public GetFieldInvoker(Field field) {
this.field = field;
}
/**
* 调用 target 对象的 字段,并返回字段值
* @param target
* @param args
* @return
* @throws IllegalAccessException
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException {
try {
return field.get(target);
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
field.setAccessible(true);
return field.get(target);
} else {
throw e;
}
}
}
/**
* 返回字段的数据类型
* @return
*/
@Override
public Class<?> getType() {
return field.getType();
}
}
SetFieldInvoker
类字段 set 方法的封装
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();
}
}
MethodInvoker
一个类的 getter 和 setter 方法的封装,方便反射调用,这个类的getter 和 setter 方法,进行 属性赋值。
public class MethodInvoker implements Invoker {
// getter、setter 方法的类型
private final Class<?> type; //java.lang.Long
// getter、setter 方法
private final Method method; //public java.lang.Long org.apache.ibatis.reflection.ReflectorTest$AbstractEntity.getId()
public MethodInvoker(Method method) {
this.method = method;
//set()
if (method.getParameterTypes().length == 1) {
type = method.getParameterTypes()[0];
} else {
//get()
type = method.getReturnType();
}
}
/**
* 调用 target 对象的 getter、setter 方法
* @param target
* @param args
* @return
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
@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;
}
}
}
/**
* 返回 getter 方法的返回数据类型,setter 方法的参数类型
* @return
*/
@Override
public Class<?> getType() {
return type;
}
}
AmbiguousMethodInvoker
一个类的属性的 getter、setter 方法时多个时,不确定哪一个是的 标志类,方便后续使用的时候报错。
public class AmbiguousMethodInvoker extends MethodInvoker {
// getter、setter 方法不确实时的错误信息
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);
}
}
网友评论