mybatis封装了自己的反射类工具箱。
Reflector类中:
构造方法如下:解析指定class队形,填充如下集合
public Reflector(Class<?> clazz) { type = clazz;//初始化clazz字段 addDefaultConstructor(clazz);//查找clazz默认构造方法 addGetMethods(clazz);//处理clazz中getter方法,填充getMethods集合和getTypes集合 addSetMethods(clazz);//处理clazz中setter方法,填充setMethods集合和setTypes集合 addFields(clazz);//处理无setter/getter方法的字段 //根据getMethods/setMethods集合,初始化可读/写属性的名称集合 readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); for (String propName : readablePropertyNames) {//初始化caseInsensitivePropertyMap(记录了所有属性名称)集合,其中记录了所有大写格式属性名称 caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writeablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } }
调用了
private void addDefaultConstructor(Class<?> clazz) { Constructor<?>[] consts = clazz.getDeclaredConstructors();//获取构造方法的参数类型 for (Constructor<?> constructor : consts) { if (constructor.getParameterTypes().length == 0) {//若为无参构造函数(默认构造函数) if (canAccessPrivateMethods()) {//安全管理器已做检查通过则返回ture否则抛出异常返回false try { constructor.setAccessible(true);//将 accessible 标志设置为指示的布尔值,值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,从而提高了性能。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 } catch (Exception e) { // Ignored. This is only a final precaution, nothing we can do. 忽略。 这只是最后的预防措施,我们做不了什么。 } } if (constructor.isAccessible()) {//获取上面的Accessible的flag值(true或者false) this.defaultConstructor = constructor; } } } }
addGetMethods()解析类中定义的getter方法
先调用getClassMethods,如下所示,接着
private Method[] getClassMethods(Class<?> cls) {//该方法获取当前类及父类中定义的所有方法的唯一签名和对应Method对象 //用于记录指定类中定义的全部方法的唯一签名及对应Method对象 Map<String, Method> uniqueMethods = new HashMap<String, Method>(); Class<?> currentClass = cls; while (currentClass != null) { //记录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()); } currentClass = currentClass.getSuperclass();//获取父类继续循环 } Collection<Method> methods = uniqueMethods.values(); return methods.toArray(new Method[methods.size()]);//转成methods数组返回 }
//返回值类型#方法名称:参数类型列表。例如:Reflector.getSignature(Method)方法唯一签名是:java.lang.String#getSignature:java.lang.reflect.Method 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(); }
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {//为每个方法生成唯一签名,记录到uniqueMethods集合中 for (Method currentMethod : methods) { if (!currentMethod.isBridge()) {//桥接方法,JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法 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()) {//安全管理器已做检查通过则返回ture否则抛出异常返回false try { currentMethod.setAccessible(true);//将 accessible 标志设置为指示的布尔值,值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,从而提高了性能。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 } catch (Exception e) { // Ignored. This is only a final precaution, nothing we can do. //忽略。 这只是最后的预防措施,我们做不了什么 } } //记录该签名和方法的对应关系 uniqueMethods.put(signature, currentMethod); } } } }
/** 解决冲突 */ 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(); /* * 两个方法的返回值类型一致,若两个方法返回值类型均为 boolean,则选取 isXXX 方法 * 为 winner。否则无法决定哪个方法更为合适,只能抛出异常 */ 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."); /* * 如果方法返回值类型为 boolean,且方法名以 "is" 开头, * 则认为候选方法 candidate 更为合适 */ } else if (candidate.getName().startsWith("is")) { winner = candidate; } /* * winnerType 是 candidateType 的子类,类型上更为具体, * 则认为当前的 winner 仍是合适的,无需做什么事情 */ } else if (candidateType.isAssignableFrom(winnerType)) { /* * candidateType 是 winnerType 的子类,此时认为 candidate 方法更为合适, * 故将 winner 更新为 candidate */ } 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."); } } // 将筛选出的方法添加到 getMethods 中,并将方法返回值添加到 getTypes 中 addGetMethod(propName, winner); } }
private void addGetMethod(String name, Method method) { if (isValidPropertyName(name)) {//检测属性名是否合法,即属性名不能以'$'开头且不能等于'class','serialVersionUID' getMethods.put(name, new MethodInvoker(method));//将属性名及对应MethodInvoker对象添加到getMethods集合中 Type returnType = TypeParameterResolver.resolveReturnType(method, type);//获取返回值type getTypes.put(name, typeToClass(returnType));//将属性名及getter方法返回值类型添加到getTypes集合中保存 } }
private void addGetMethods(Class<?> cls) { Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>(); //conflictingGetters 集合key是属性名,value是getter方法集合,由于子类可能覆写父类getter方法,所以同一属性名会有多个getter方法 Method[] methods = getClassMethods(cls);//获取制定类及父类和接口中定义的方法 for (Method method : methods) {// if (method.getParameterTypes().length > 0) { continue; } String name = method.getName(); //javaBean中getter方法的方法名长度以"get"开头并且长度大于3或者以"is"开头并且长度大于2 if ((name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2)) { name = PropertyNamer.methodToProperty(name);//截取掉get或者is获取后面实际的对应属性名称 addMethodConflict(conflictingGetters, name, method);//若此方法在conflictingGetters中没有,则放入key是属性名 和value 是getter方法集合否则只放入list集合中的方法 } } resolveGetterConflicts(conflictingGetters);//调用上面解决冲突的方法 }
private void addFields(Class<?> clazz) {//处理类中定义所有字段,并在处理后添加到setMethods集合,setTypes集合,getMethods集合以及getTypes集合中 Field[] fields = clazz.getDeclaredFields();//获取clazz中定义的所有字段 for (Field field : fields) { if (canAccessPrivateMethods()) {//安全管理器已做检查通过则返回ture否则抛出异常返回false try { field.setAccessible(true);//将 accessible 标志设置为指示的布尔值,值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,从而提高了性能。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 } catch (Exception e) { // Ignored. This is only a final precaution, nothing we can do. //忽略。 这只是最后的预防措施,我们做不了什么 } } if (field.isAccessible()) {当字段修饰符为private时,我们需要加上,否则会抛出异常 if (!setMethods.containsKey(field.getName())) {//当setMethods集合不包含同名属性时,将其记录到setMethods集合和setTypes集合 // 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))) {//过滤掉final和static修饰的字段 addSetField(field);//填充setMethods集合和setTypes集合,与上述addGetMethod类似 } } if (!getMethods.containsKey(field.getName())) {//当getMethods集合不包含同名属性时,将其记录到getMethods集合和getTypes集合 addGetField(field);//填充getMethods集合和getTypes集合,与上述addGetMethod类似 } } } if (clazz.getSuperclass() != null) {//有父类 addFields(clazz.getSuperclass());//递归调用,处理父类中定义字段 } }
Invoker:
public interface Invoker { Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;//调用获取指定字段或执行的方法 Class<?> getType();//返回属性相应类型 }
只有三个实现如下:
public class GetFieldInvoker implements Invoker { private final Field field; public GetFieldInvoker(Field field) { this.field = field; } @Override public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException { return field.get(target);//方法返回指定对象上由此Field表示的字段的值。如果该对象具有原始类型,则该值将自动包装在对象中。 } @Override public Class<?> getType() { return field.getType(); } }
SetFieldInvoker与GetFieldInvoker相类似
MethodInvoker的invoker调用Method.invoker实现的
由ReflectorFactory接口实现对Reflector对象创建与缓存
public interface ReflectorFactory { boolean isClassCacheEnabled();//该ReflectorFactory对象是否缓存Reflector对象 void setClassCacheEnabled(boolean classCacheEnabled);//设置是否缓存Reflector对象 Reflector findForClass(Class<?> type);//创建指定Class对应的Reflector对象 }
只有一个实现上述接口的实现类:DefaultReflectorFactory
public class DefaultReflectorFactory implements ReflectorFactory { private boolean classCacheEnabled = true;//是否开启对Reflector对象的缓存 private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();//使用ConcurrentMap集合实现对 Reflector对象的缓存 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 Reflector cached = reflectorMap.get(type); if (cached == null) { cached = new Reflector(type);//创建Reflector对象 reflectorMap.put(type, cached);//放入ConcurrentMap中缓存 } return cached; } else { return new Reflector(type);//没开启缓存则直接创建新对象返回 } } }