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 public class Reflector { 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); } } }
添加默认构造函数
对应属性defaultConstructor
1 2 3 4 5 6 7 8 9 10 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 private void addGetMethods (Class<?> clazz) { Map<String, List<Method>> conflictingGetters = new HashMap <>(); Method[] methods = getClassMethods(clazz); 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 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)) { } 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); } }
getMethods方法
填充reflector属性 getMethods, getTypes
1 2 3 4 5 6 7 8 9 10 11 12 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 private void addFields (Class<?> clazz) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (!setMethods.containsKey(field.getName())) { 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()); } }
addSetField方法
对于某些字段没有些setter和getter的属性,mybatis会自动创建setter和getter方法。
1 2 3 4 5 6 7 8 9 10 11 12 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 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 { boolean isClassCacheEnabled () ; void setClassCacheEnabled (boolean classCacheEnabled) ; 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 ; 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) { 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 public interface ObjectFactory { default void setProperties (Properties properties) { } <T> T create (Class<T> type) ; <T> T create (Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) ; <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 @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 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) { 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 @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 @SuppressWarnings("unchecked") @Override public <T> T create (Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { Class<?> classToCreate = resolveInterface(type); return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs); } 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()) { 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); } }