1、概述
Mybatis的org.apache.ibatis.reflection包下,是Mybatis反射模块的代码集合,包结构如下所示。其中,Reflector是Mybatis中反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射操作需要使用的类的元信息。ReflectorFactory接口主要是为了实现对Reflector对象的创建和缓存,Mybatis为ReflectorFactory接口提供了一个默认实现类DefaultReflectorFactory,其中findForClass()方法实现会为指定的Class创建Reflector对象,并将Reflector 对象缓存到reflectorMap中。
2、Reflector类
Reflector是Mybatis中反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射操作需要使用的类的元信息。
- 字段
//对应的Class类型
private final Class<?> type;
//可读属性的名称集合,可读属性就是存在相应getter方法的属性,初始值为空数纽
private final String[] readablePropertyNames;
//可写属性的名称集合,可写属性就是存在相应setter方法的属性,初始值为空数纽
private final String[] writeablePropertyNames;
//属性相应的setter方法,key是属性名称,value是Invoker对象,它是对setter方法对应Method对象的封装
private final Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
//属性相应的getter方法集合, key是属性名称, value也是Invoker对象
private final Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
//属性相应的setter方法的参数值类型, key是属性名称, value是setter方法的参数类型
private final Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
//属性相应的getter方法的返回位类型, key是属性名称, value是getter方法的返回类型
private final Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
//默认构造方法
private Constructor<?> defaultConstructor;
//所有属性名称的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();
- 构造函数
在构造函数中,主要实现了对类的元信息进行解析和缓存,即初始化相关字段数据。下面分别分析数据初始化的过程。其中,type字段就是class,所以下面不再重复分析。
/**
* 解析指定的Class对象,填充相应的属性
* @param clazz
*/
public Reflector(Class<?> clazz) {
type = clazz;//初始化type字段
//查找clazz的默认构造方法(无参构造方法),具体实现是通过反射遍历所有构造方法
addDefaultConstructor(clazz);
//处理clazz中的getter方法,填充getMethods集合和getTypes集合
addGetMethods(clazz);
//处理clazz中的setter方法,填充setMethods集合和setTypes集合
addSetMethods(clazz);
//处理没有getter/setter方法的字段
addFields(clazz);
//根据getMethods/setMethods集合,初始化可读/写属性的名称集合
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
//初始化caseinsensitivePropertyMap集合,其中记录了所有大写格式的属性名称
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
- addDefaultConstructor()方法 初始化默认构造函数
查找clazz的默认构造方法,即无参构造方法,具体实现是通过反射遍历所有构造方法,然后通过过滤查询到默认构造函数,并赋值给defaultConstructor字段。
private void addDefaultConstructor(Class<?> clazz) {
Constructor<?>[] consts = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : consts) {//循环,查询符合条件的构造函数
if (constructor.getParameterTypes().length == 0) {
if (canAccessPrivateMethods()) {
try {
constructor.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (constructor.isAccessible()) {
this.defaultConstructor = constructor;
}
}
}
}
- addGetMethods()方法 处理clazz中的getter方法
处理clazz中的getter方法,并填充getMethods集合和getTypes集合。解析getter方法的过程,经过了一系列的方法和逻辑处理,最终达到了获取getter方法对应字段的目的。下面逐步分析:
首先,分析addGetMethods()方法,代码如下。其中,包含了getClassMethods()方法,主要用来获取当前类以及其父类中定义的所有方法的唯一签名以及相应的Method对象;addMethodConflict()方法,主要用来获取字段名和字段名对应的getter方法的映射集合,并把结果保存到conflictingGetters变量中;resolveGetterConflicts()方法,主要用来处理重复的方法。注意:一个key会对应多个method的原因是:当子类覆盖了父类的getter方法且返回值发生变化时,会产生两个签名不同的方法。
private void addGetMethods(Class<?> cls) {
//记录所有符合条件的getter方法的Method对象
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
Method[] methods = getClassMethods(cls);
for (Method method : methods) {//循环,判断getter方法,并填充相应集合
if (method.getParameterTypes().length > 0) {//getter方法一定没有参数,所以首先排除有参数的方法
continue;
}
String name = method.getName();
if ((name.startsWith("get") && name.length() > 3)
|| (name.startsWith("is") && name.length() > 2)) {//判断getter方法,即is或getter开头的方法
//根据Method对象的方法名称,获取getter或setter方法对应的属性名称
name = PropertyNamer.methodToProperty(name);
//把属性名作为key,属性名对应的所有的method对象的集合作为值,然后填充到conflictingMethods中
addMethodConflict(conflictingGetters, name, method);
}
}
resolveGetterConflicts(conflictingGetters);
}
getClassMethods()方法,通过while循环,加载当前类及其所有父类中对应的Method对象,并把这些Method对象存储到了uniqueMethods对象中,其中唯一签名作为key,Method对象作为value值,即用来获取当前类以及其父类中定义的所有方法的唯一签名以及相应的Method对象。
private Method[] getClassMethods(Class<?> cls) {
//记录指定类中定义的全部方法的唯一签名以及对应的Method对象
Map<String, Method> uniqueMethods = new HashMap<String, Method>();
Class<?> currentClass = cls;
while (currentClass != null && currentClass != Object.class) {
//记录currentClass这个类中定义的全部方法
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());
}
//迭代,直到Object类终止循环迭代(获取父类,继续while循环)
currentClass = currentClass.getSuperclass();
}
//获取所有的method对象,并转换成数字返回
Collection<Method> methods = uniqueMethods.values();
return methods.toArray(new Method[methods.size()]);
}
addUniqueMethods()方法,主要是为第二个参数, methods数组中的每个Method对象生成唯一签名,井记录到uniqueMethods变量中,根据生成的签名判断,如果已经添加过,就不再重复添加。
注意:虽然添加了重复判断,但是还是可能出现重复记录,因为当子类覆盖了父类的getter方法且返回值发生变化时,会产生两个签名不同的方法。
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
for (Method currentMethod : methods) {
if (!currentMethod.isBridge()) {//排除bridge方法
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
//检测是否在子类中已经添加过该方法,如果在子类中已经添加过, 则表示子类覆盖了该方法,
//无须再向uniqueMethods集合中添加该方法了
if (!uniqueMethods.containsKey(signature)) {
if (canAccessPrivateMethods()) {
try {
currentMethod.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
uniqueMethods.put(signature, currentMethod);
}
}
}
}
getSignature()方法,生成方法的签名,得到的方法签名是全局唯一的,可以作为该方法的唯一标识, 格式:返回值类型#方法名称:参数类型列表;例如:Reflector.getSignature(Method)方法的唯一签名是:java.lang.String#getSignature:Java.lang.reflect.Method
/**
* 生成方法的签名,得到的方法签名是全局唯一的,可以作为该方法的唯一标识
* 格式:返回值类型#方法名称:参数类型列表
* 例如:Reflector.getSignature(Method)方法的唯一签名是:java.lang.String#getSignature:Java.lang.reflect.Method
* @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++) {
if (i == 0) {
sb.append(':');
} else {
sb.append(',');
}
sb.append(parameters[i].getName());
}
return sb.toString();
}
addMethodConflict()方法用来把getClassMethods()方法中得到的Method数组(getter方法),根据字段名进行分类,对应的getter方法可能有多个(因为当子类覆盖了父类的getter方法且返回值发生变化时,会产生两个签名不同的方法,所以一个字段对应多个Method方法),所以addMethodConflict()方法,会把处理结果存储到Map<String, List>类型的conflictingGetters变量中。
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
List<Method> list = conflictingMethods.get(name);
if (list == null) {
list = new ArrayList<Method>();
conflictingMethods.put(name, list);
}
list.add(method);
}
resolveSetterConflicts()方法,用来把上一步addMethodConflict()方法产生的conflictingGetters数据中重复的Method对象进行处理,变成一个字段对应一个Method对象形式的数据,然后通过addGetMethod()方法把对应key和value存到变量getMethods和getTypes中。
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,跳过当前循环继续和后面的比较
winner = candidate;
continue;
}
Class<?> winnerType = winner.getReturnType();
Class<?> candidateType = candidate.getReturnType();
if (candidateType.equals(winnerType)) {//特殊处理返回值是boolean类型的方法
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;
}
//isAssignableFrom(),判定此 Class对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。如果是则返回 true;否则返回 false
} 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.");
}
}
addGetMethod(propName, winner);
}
}
在addGetMethod()方法中,主要是把对应key和value存到变量getMethods和getTypes中。其中,key对应的是字段name,value对应的是把method对象封装成的Invoker对象。
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));
}
}
public interface Invoker {
/**
* 执行调用
* 主要用于执行:getter方法、setter方法和Field的get和set
* @param target
* @param args
* @return
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
/**
* 差异:
* 1.getter方法 返回返回类型
* 2.setter方法 返回参数类型
* 3.Field返回自身的类型
* @return
*/
Class<?> getType();
}
/**
* 获取字段类型和字段在对应对象中的值,即Field get属性执行器
* @author Clinton Begin
*/
public class GetFieldInvoker implements Invoker {
//Field对象 即被适配者
private final Field field;
public GetFieldInvoker(Field field) {
this.field = field;
}
/**
* 获取 target Field的属性值
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return field.get(target);
}
/**
* 返回Field的类型
*/
@Override
public Class<?> getType() {
return field.getType();
}
}
public class MethodInvoker implements Invoker {
/**
* getter方法 返回返回类型
* setter方法 返回参数类型
*/
private final Class<?> type;
/**
* Method对象 即被适配者
*/
private final Method method;
/**
* 构造函数,根据Method对象解析对应的type
* @param method
*/
public MethodInvoker(Method method) {
this.method = method;
if (method.getParameterTypes().length == 1) {
type = method.getParameterTypes()[0];
} else {
type = method.getReturnType();
}
}
/**
* 执行method对象对应的方法
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return method.invoke(target, args);
}
/**
* getter方法 返回返回类型
* setter方法 返回参数类型
*/
@Override
public Class<?> getType() {
return type;
}
}
public class SetFieldInvoker implements Invoker {
private final Field field;
public SetFieldInvoker(Field field) {
this.field = field;
}
/**
* 设置 target Field的属性值
*/
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
field.set(target, args[0]);
return null;
}
/**
* 返回Field类型
*/
@Override
public Class<?> getType() {
return field.getType();
}
}
-
addSetMethods()方法 处理clazz中的setter方法
addSetMethods()方法的处理逻辑和addGetMethods()方法的处理逻辑基本相同,可以直接看着源码进行学习,本处不再重复分析。 -
addFields()方法 处理没有getter/setter方法的字段
private void addFields(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (canAccessPrivateMethods()) {
try {
field.setAccessible(true);
} catch (Exception e) {
// Ignored. This is only a final precaution, nothing we can do.
}
}
if (field.isAccessible()) {
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))) {
addSetField(field);
}
}
if (!getMethods.containsKey(field.getName())) {
addGetField(field);
}
}
}
if (clazz.getSuperclass() != null) {
addFields(clazz.getSuperclass());
}
}
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));
}
}
2、ReflectorFactory类
ReflectorFactory接口主要是为了实现对Reflector对象的创建和缓存,Mybatis为ReflectorFactory接口提供了一个默认实现类DefaultReflectorFactory,其中findForClass()方法实现会为指定的Class创建Reflector对象,并将Reflector 对象缓存到reflectorMap中。
public interface ReflectorFactory {
/**
* 检测该ReflectorFactory对象是否会缓存Reflector对象
* @return
*/
boolean isClassCacheEnabled();
/**
* 设置是否缓存Reflector对象
* @param classCacheEnabled
*/
void setClassCacheEnabled(boolean classCacheEnabled);
/**
* 创建指定Class对应的Reflector对象
* @param type
* @return
*/
Reflector findForClass(Class<?> type);
}
public class DefaultReflectorFactory implements ReflectorFactory {
//该字段决定是否开启对Reflector对象的缓存
private boolean classCacheEnabled = true;
//使用ConcurrentMap集合实现对Reflector对象的缓存
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();
public DefaultReflectorFactory() {
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
/**
* 实现会为指定的Class创建Reflector对象,并将Reflector对象缓存到reflectorMap中。
*/
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
Reflector cached = reflectorMap.get(type);
if (cached == null) {
cached = new Reflector(type);
reflectorMap.put(type, cached);
}
return cached;
} else {
return new Reflector(type);
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68911.html