在Java中,反射是一种十分强大且灵活的机制,但是其使用门槛相对较高。而Mybatis中就封装了一个反射工具箱,可以更易于使用
反射工具箱的具体实现位于org.apache.ibatis.reflection中。
下面我们来简单解释下其主要构成。
Reflector
Reflector是其中一个很重要的类。这是一个用于缓存类的映射集。
在构造一个Reflector对象时,是通过传入一个Class对象来实现的。
其主要的属性:
private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writablePropertyNames;
private final Map<String, Invoker> setMethods = new HashMap<>();
private final Map<String, Invoker> getMethods = new HashMap<>();
private final Map<String, Class<?>> setTypes = new HashMap<>();
private final Map<String, Class<?>> getTypes = new HashMap<>();
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
首先,我们可以看看其主要的逻辑。
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);
}
}
传入一个Class类对象,然后使用type记录该Class的类型。 通过addDefaultConstructor(clazz)方法来初始化默认的构造方法。 addDefaultConstructor()的内部:
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
Arrays.stream(constructors).filter(constructor -> constructor.getParameterTypes().length == 0)
.findAny().ifPresent(constructor -> this.defaultConstructor = constructor);
}
可知,该方法是通过反射获取Class内部的所有构造方法,并遍历,最后过滤出一个无参构造方法,从而初始化defaultConstructor字段。