抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

MYBATIS反射模块

简介

​ MyBatis在进行参数处理、结果映射时等操作时,会涉及大量的反射操作。为了简化这些反射相关操作,MyBatis 在 org.apache.ibatis.reflection 包下提供了专门的反射模块,对反射操作做了近一步封装,提供了更为简洁的 API。

Reflector相关类

MyBatis 提供 Reflector 类来缓存类的字段名和 getter/setter 方法的元信息,使得反射时有更好的性能。使用方式是将原始类对象传入其构造方法,生成 Reflector 对象。

Reflector类

属性和构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 对应class 的反射封装
*
* @author Clinton Begin
*/
public class Reflector {
/**
* 对应class 的类型
*/
private final Class<?> type;
//可读属性数组
private final String[] readablePropertyNames;
//可写属性列表
private final String[] writablePropertyNames;
//setter方法列表
private final Map<String, Invoker> setMethods = new HashMap<>();
//getter方法列表
private final Map<String, Invoker> getMethods = new HashMap<>();
//set方法map
private final Map<String, Class<?>> setTypes = new HashMap<>();
//get方法map
private final Map<String, Class<?>> getTypes = new HashMap<>();
//默认构造器
private Constructor<?> defaultConstructor;
//大小写不敏感属性名称列表
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

/**
* 构造方法
*
* @param clazz
*/
public Reflector(Class<?> clazz) {
type = clazz;
// 如果存在,记录无参构造方法
addDefaultConstructor(clazz);
// 记录字段名与get方法、get方法返回值的映射关系
addGetMethods(clazz);
// 记录字段名与set方法、set方法参数的映射关系
addSetMethods(clazz);
// 针对没有getter/setter方法的字段,通过Filed对象的反射来设置和读取字段值
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);
}
}
}
添加默认构造函数

对应属性defaultConstructor

1
2
3
4
5
6
7
8
9
10
/**
* 添加默认的构造方法
*
* @param 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);
}
注册getter和setter方法

addGetMethods 和 addSetMethods 分别获取类的所有方法,从符合 getter/setter 规范的方法中解析出字段名,并记录方法的参数类型、返回值类型等信息

addGetMethods方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 添加GetMethod
*
* @param clazz
*/
private void addGetMethods(Class<?> clazz) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
//返回这个类及其父类的所以methods
Method[] methods = getClassMethods(clazz);
//过滤为无参的method
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
resolveGetterConflicts(conflictingGetters);
}

resolveGetterConflicts方法

​ 如果子类覆盖父类的gettter方法,并且返回值发生变化,就会生成2个签名。例如有类 A 及其子类 SubA, A 类中定 义了 getNames()方法,其返回值类型是 List ,而在其子类 SubA 中, 覆写了其 getNames()方法且将返回值修改成 ArrayList 类型,这种覆写在 Java语言中是合法的。最终得到 的两个方法签名分别是 java.util.List#getNames 和 java.util.ArrayList#getNames,在 Reflector.addUniqueMethods()方法中会被认为是两个不同的 方法并添加到 uniqueMethods 集合中。
Reflector.resolveGetterConflicts()方法对这种覆写 的情况进行处理,同时会将处理得到的 getter方法记录到 getMethods集合,并将其返回值类型填充到 getTypes集合 。 Reflector.resolveGetterConflicts()方法的具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 去重 判断非法的get方法 并将可用的get方法加入到getMethods
*
* @param conflictingGetters
*/
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
Method winner = null;
String propName = entry.getKey();
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)) {
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
} else if (candidate.getName().startsWith("is")) {
winner = candidate;
}
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
} else if (winnerType.isAssignableFrom(candidateType)) {
winner = candidate;
} else {
throw new ReflectionException(
"Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + winner.getDeclaringClass()
+ ". This breaks the JavaBeans specification and can cause unpredictable results.");
}
}
//调用 getMethod 添加getMethod
addGetMethod(propName, winner);
}
}
getMethods方法

填充reflector属性 getMethods, getTypes

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 添加getMethod
* @param name
* @param method
*/
private void addGetMethod(String name, Method method) {
if (isValidPropertyName(name)) {
getMethods.put(name, new MethodInvoker(method));
Type returnType = TypeParameterResolver.resolveReturnType(method, type);
getTypes.put(name, typeToClass(returnType));
}
}
addFields方法

Reflector.addFields()方法会处理类中定义的所有字段 , 并且将处理后的字段信息添加到 setMethods 集合、 setTypes 集合、 getMethods 集合以及 getTypes 集合中,这一点与上述的 Reflector.addGetMethods()方法是一致 的 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 添加字段列表
*
* @param clazz
*/
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//如果set方法列表中没有属性
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();
//字段不是 final 类型的并且 不是 静态的
if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
//添加setField构建的方法
addSetField(field);
}
}
//如果getMethod中没有对应的get方法
if (!getMethods.containsKey(field.getName())) {
//添加getField构建的方法
addGetField(field);
}
}
//父类字段添加到Filed 列表
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
addSetField方法

对于某些字段没有些setter和getter的属性,mybatis会自动创建setter和getter方法。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 构建一个setMethod用于属性的获取
*
* @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));
}
}
isValidPropertyName 方法

对于一些字段是不需要进行生成getter和setter方法的

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 验证属性名称
* 不嫩以$ 开头 不是代理的
* 不是serialVersionUID 序列化字段
* 并且不是class 属性
*
* @param name
* @return
*/
private boolean isValidPropertyName(String name) {
return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
}

ReflectorFactory接口

反射工厂接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 反射工厂接口
*/
public interface ReflectorFactory {
/**
* class 释放已经混村
* @return
*/
boolean isClassCacheEnabled();

/**
* 设置class缓存状态
* @param classCacheEnabled
*/
void setClassCacheEnabled(boolean classCacheEnabled);

/**
* 获取对应class的反射类
* @param type
* @return
*/
Reflector findForClass(Class<?> type);
}

DefaultReflectorFactory类

继承了ReflectorFactory接口增加了缓存等功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 默认反射工程
*/
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
//线程安全的hashMap
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
//存在则则返回 否则创建
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}

factory包

该包中包含的内容比较少,一个接口,一个实现类。

ObjectFactory接口

POJO类在创建时通常也就两类操作:

  • 初始化:分带参数和不带参数两种
  • 属性赋值。

​ 因而ObjectFactory接口也包含了这样的函数,同时考虑到mybatis配置时的特点,添加了一个额外的函数,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

/**
* Object 对象工厂
*
* @author Clinton Begin
*/
public interface ObjectFactory {

/**
* 设置一些配置书香
* @param properties
*/
default void setProperties(Properties properties) {
// NOP
}

/**
* 利用默认构造函数创建对象
* @param type
* @param <T>
* @return
*/
<T> T create(Class<T> type);

/**
* //利用带有参数的构造函数创建对象
* @param type
* @param constructorArgTypes
* @param constructorArgs
* @param <T>
* @return
*/
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

/**
* 是否是集合
* @param type
* @param <T>
* @return
*/
<T> boolean isCollection(Class<T> type);

}

DefaultObjectFactory接口

默认的对象工厂的实现,是对ObjectFactory的具体实现

MyBatis每次创建结果对象的新实例时,使用ObjectFactory构建POJO

create函数合并

上面我们提到初始化对象时可以调用默认构造函数和带有参数的构造函数,DefaultObjectFactory在实现时直接进行了二次包装,将两个函数的实现合二为一。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 对默认创建构造方法进行包装
* 进行调用create重载
* @param type
* @param <T>
* @return
*/
@Override
public <T> T create(Class<T> type) {
//调用具体的实现
return create(type, null, null);
}
根据接口获取实现类

在面向对象的开发中我们会提倡面对接口而不是面向具体实现的编程原则,但是在创建对象时则必须指定一个具体的类,为了解决这个问题,mybatis对常用的集合超类指定了具体的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 根据接口获取具体的实现
* @param type
* @return
*/
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) { // issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
判断是否是集合
1
2
3
4
5
6
7
8
9
10
/**
* 判断是否是集合
* @param type
* @param <T>
* @return
*/
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
构造方法创建对象

准备工作完成了,下面我们来了解下具体的创建过程,虽然有些复杂,但是对于了解java的反射机制和类安全会有帮助:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* 构造方法创建对象的具体实现
*
* @param type 对象类型
* @param constructorArgTypes 构造方法类型
* @param constructorArgs 构造方法参数
* @param <T> 返回具体的对象
* @return
*/
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
//判断类是不是集合类,如果是集合类指定具体的实现类
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}

/**
* 实例化类
*
* @param type
* @param constructorArgTypes
* @param constructorArgs
* @param <T>
* @return
*/
private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
//通过无参构造函数创建对象
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
try {
return constructor.newInstance();
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
//必须设置为true,否则在下面的调用时会抛出IllegalAccessException
constructor.setAccessible(true);
return constructor.newInstance();
} else {
throw e;
}
}
}
//根据指定的参数列表查找构造函数,并实例化对象
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
try {
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} else {
throw e;
}
}
} catch (Exception e) {
String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
.stream().map(Class::getSimpleName).collect(Collectors.joining(","));
String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
.stream().map(String::valueOf).collect(Collectors.joining(","));
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}

评论