該模塊位於org.apache.ibatis.reflection
包中,MyBatis在進行參數處理、結果映射等操做時,會涉及大量的反射操做。Java 中的反射雖然功能強大,可是代碼編寫起來比較複雜且容易出錯,爲了簡化反射操做的相關代碼,MyBatis提供了專門的反射模塊,它對常見的反射操做作了進一步封裝,提供了更加簡潔方便的反射API。本節就來爲讀者介紹該模塊中核心代碼的實現。java
Reflector 是MyBaits中反射模塊的基礎,Reflector中緩存了不少反射操做須要使用的元數據。各個字段以下:apache
private final Class<?> type; //對應的class類型 private final String[] readablePropertyNames; //可讀屬性的名稱集合,可讀屬性就是存在相應getter方法的屬性 private final String[] writablePropertyNames; //可寫屬性的名稱集合,可寫屬性就是存在相應setter方法的屬性 //記錄了屬性相應的setter方法,key是屬性名稱,value 是Invoker對象,它是對setter方法對應 // Method 對象的封裝 private final Map<String, Invoker> setMethods = new HashMap<>(); //屬性相應的getter方法集合,key 是屬性名稱,value 也是Invoker對象 private final Map<String, Invoker> getMethods = new HashMap<>(); //記錄了屬性相應的setter方法的參數值類型,key是屬性名稱,value是setter方法的參數類型 private final Map<String, Class<?>> setTypes = new HashMap<>(); //記錄了屬性相應的getter方法的參數值類型,key是屬性名稱,value是getter方法的參數類型 private final Map<String, Class<?>> getTypes = new HashMap<>(); //記錄了默認的構造函數 private Constructor<?> defaultConstructor; //記錄了全部屬性名稱的集合 private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
在Reflector的構造函數中,會解析指定的Class對象,並填充上述集合,代碼以下:數組
public Reflector(Class<?> clazz) { type = clazz; //初始化type字段 //查找默認構造函數(無參構造函數)具體實現是以反射遍歷全部構造方法 addDefaultConstructor(clazz); //處理class中的getter方法 addGetMethods(clazz); //處理class中的setter方法 addSetMethods(clazz); //處理沒有getter或setter方法的字段 addFields(clazz); // 初始化爲空數組 readablePropertyNames = getMethods.keySet().toArray(new String[0]); // 初始化爲空數組 writablePropertyNames = setMethods.keySet().toArray(new String[0]); //初始化caseInsensitivePropertyMap集合 其中記錄了全部大寫格式的屬性名稱 for (String propName : readablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } }
Reflector.addGetMethods()方法主要解析類中定義的getter方法,Reflector.addSetMethods()方法主要解析類中定義的setter方法,兩個相似,下面咱們就以Reflector.addGetMethods()方法爲例進行介紹,Reflector.addGetMethods()解析有下面三個步驟:緩存
首先調用Reflector.getClassMethods()方法獲取當前類以及父類中定義的全部方法的惟一簽名以及相應的Method對象。微信
private Method[] getClassMethods(Class<?> clazz) { //用於記錄指定類中定義的所有方法的惟一簽名對應的Method對象 Map<String, Method> uniqueMethods = new HashMap<>(); Class<?> currentClass = clazz; 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()); } //獲取父類繼續while循環 currentClass = currentClass.getSuperclass(); } Collection<Method> methods = uniqueMethods.values(); //轉換成methods數組返回 return methods.toArray(new Method[0]); }
在Reflector.getClassMethods()方法中會爲每一個方法生成惟一簽名,並記錄到conflictingSetters集合中,實現以下:mybatis
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) { for (Method currentMethod : methods) { if (!currentMethod.isBridge()) { //經過getSignature()方法獲得的方法簽名 規則:返回值類型#方法名稱:參數類型列表。 //經過getSignature()方法獲得的發放簽名是全局惟一的,能夠做爲該方法的惟一標識 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 //檢測是否在子類中已經添加過該方法【若是添加過就忽略】 if (!uniqueMethods.containsKey(signature)) { //記錄該簽名和方法的對應關係 uniqueMethods.put(signature, currentMethod); } } } }
而後按照Java規範,從Reflector.getClassMethods()方法返回的Method數組中查找該類的getter方法,記錄到conflictingSetters集合中。【該集合爲HashMap<String,<List<Method>>>
,key爲屬性名稱,value是該屬性對應的setter集合。】app
當子類覆蓋父類的getter方法且返回值發生變化時,在步驟【1】中就會產生兩個簽名不一樣的方法,在Reflector.addUniqueMethods()方法中會被當作兩個不一樣的方法添加到conflictingSetters集合中,這顯然不是咱們要的結果,因此第三步咱們會調用Reflector.resolveSetterConflicts()方法對這個覆寫的方法進行處理,同時會將獲得的getter方法記錄到getMethods集合,並將其返回值類型填充到getTypes集合。Reflector.resolveSetterConflicts()方法具體實現以下:函數
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) { // 遍歷 conflictingGetters 集合 for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) { Method winner = null; //獲取屬性名 String propName = entry.getKey(); //是不是不明確的 boolean isAmbiguous = false; // 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)) { //不明確的類型 【不明確 拋異常】 isAmbiguous = true; break; } else if (candidate.getName().startsWith("is")) { //對於boolean類型 //當前方法返回值是當前最合適的方法的返回值的子類 winner = candidate; } } else if (candidateType.isAssignableFrom(winnerType)) { //當前最適合的方法的返回值是當前方法返回值的子類,什麼都不作 當前最適合的方法 依然不變 // OK getter type is descendant } else if (winnerType.isAssignableFrom(candidateType)) { //當前返回值是當前最適合的方法的返回值的 winner = candidate; } else { //不明確的類型 要拋異常 isAmbiguous = true; break; } } addGetMethod(propName, winner, isAmbiguous); } }
Reflector.addGetMethod()方法對getMethods集合和getTypes集合進行填充,具體實現代碼以下:工具
private void addGetMethod(String name, Method method, boolean isAmbiguous) { //對於不明確的方法 拋異常處理 MethodInvoker invoker = isAmbiguous ? new AmbiguousMethodInvoker(method, MessageFormat.format( "Illegal overloaded getter method with ambiguous type for property ''{0}'' in class ''{1}''. This breaks the JavaBeans specification and can cause unpredictable results.", name, method.getDeclaringClass().getName())) : new MethodInvoker(method); //將屬性名以及對應的MethodInvoker對象添加到getMethods集合中,Invoker的內容後面解析 getMethods.put(name, invoker); //獲取返回值的Type,TypeParameterResolver會在後面分析 Type returnType = TypeParameterResolver.resolveReturnType(method, type); //將屬性名及其getter方法的返回值加到getTypes集合中保存,typeToClass()方法後面分析 getTypes.put(name, typeToClass(returnType)); }
分析完Reflector.addGetMethods()的三個核心步驟後,咱們看下具體實現代碼,以下:測試
private void addGetMethods(Class<?> clazz) { //conflictingGetters集合 key爲屬性名稱,value爲相應的getter方法集合,由於子類可能覆蓋父類的getter方法, //因此同一屬性的名稱可能存在多個getter方法 Map<String, List<Method>> conflictingGetters = new HashMap<>(); //步驟一:獲取指定類以及父類和接口中定義的方法 Method[] methods = getClassMethods(clazz); //步驟二:按照javabean規範查找getter方法 添加到conflictingGetters中 Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName())) .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m)); //對於getter方法進行處理 resolveGetterConflicts(conflictingGetters);
Reflector.addFields()方法會處理類中定義的全部字段,而且將處理的字段信息添加到setMethods集合、setTypes集合、getMethods集合、getTypes集合中,Reflector.addFileds()方法的實現代碼以下:
//處理類中定義的全部字段 private void addFields(Class<?> clazz) { //提取clazz中定義的全部字段 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { 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(); //過濾調static和final修飾的方法 if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) { //填充setMethods集合和setTypes集合 addSetField(field); } } //getMethods集合中不包同名屬性時,將其記錄到getMethods集合和getTypes集合中 if (!getMethods.containsKey(field.getName())) { //填充getMethods集合和getTypes集合 addGetField(field); } } if (clazz.getSuperclass() != null) { //處理父類中定義的字段 addFields(clazz.getSuperclass()); } }
Reflector中提供多個get *()方法用於讀取上述集合中的元數據信息。
add Methods()方法和add Field()方法在上述集合中添加元素的時候,會將getter/setter方法對應的Method對象以及字段對應的Field對象統一封裝成Invoker對象。Invoker接口的定義以下:
public interface Invoker { //調用指定字段的值或者指定的方法 Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException; //返回屬性相應的類型 Class<?> getType(); }
invoker接口的實現以下圖:
GetFieldInvoker/SetFieldInvoker經過field字段封裝了FIeld對象,二者的invoke()方法是經過調用Field.get()/set()方法實現的。MethodInvoker經過method字段封裝了對應的Method對象,其invoke()方法是經過調用Method.invoke()方法實現的。
ReflectorFactory接口主要實現了對Reflector對象的建立和緩存,接口定義以下:
public interface ReflectorFactory { //檢查該ReflectorFactory對象是否會緩存Reflector對象 boolean isClassCacheEnabled(); //設置是否緩存Reflector對象 void setClassCacheEnabled(boolean classCacheEnabled); //建立指定對象的Reflector對象 Reflector findForClass(Class<?> type); }
MyBatis對ReflectorFactory接口只提供了DefaultReflectorFactory這一個實現類,他與Reflector關係如圖:
DefaultReflectorFactory的字段含義以下:
//該字段決定是否對Reflector對象的緩存 private boolean classCacheEnabled = true; //使用ConcurrentHashMap集合實現對Reflector對象的緩存 private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
DefaultReflectorFactory提供findForClass()方法實現爲指定Class建立Reflector對象,並將Reflector對象緩存到reflectorMap集合中,具體代碼以下:
public Reflector findForClass(Class<?> type) { if (classCacheEnabled) { //檢測是否開啓緩存 //cas放入緩存 return reflectorMap.computeIfAbsent(type, Reflector::new); } else { //未開啓緩存則直接建立 return new Reflector(type); } }
此外除了使用MyBatis提供的DefaultReflectorFactory實現,們還能夠在mybatis-config.xml中配置自定義的ReflectorFactory實現類,從而實現上面功能的拓展。(後面會在介紹MyBatis初始化流程時,會提到拓展點。)
在分析TypeParameterResolver
以前咱們先來看下Type接口,Type是全部類型的父接口,他有四個接口和一個實現類,類圖如圖所示:
Class
:表示原始類型類型,Class對象表示JVM中一個類或者接口,每一個Java類在JVM都表現爲一個Class對象。在程序中能夠經過 」xxx.class「,」對象.getClass()"或者是Class.forName("類名")來獲取Class對象。數組也被映射爲Class對象,全部元素類型相同切維數相同的數組都共享一個Class對象。
ParameterizedType:表示參數化類型,例如List< String >,Map<Integer,String>,Service< User >這種帶有泛型的類型。
GenericArrayType
:表示的是數組類型且組成元素是ParameterizedType或者TypeVariable。例如List< String >[]或者T[]
TypeVariable
:表示的是類型變量,它用來反映在JVM編譯該泛型前的信息。例如在LIst
WildcardType
:表示通配符類型,例如:? extends Number
和? extends Integer
。
上面介紹了Type接口的基礎知識,咱們回來繼續分析TypeParameterResolver
。在對Reflector
的分析中咱們看到了TypeParameterResolver
的身影,他是一個工具類提供一些列靜態方法來解析指定類中的字段、方法返回值或者方法參數的類型。TypeParameterResolver
中各個方法之間的調用大體以下:【其中有一些遞歸調用沒有體現出來,在後面的分析中會進行強調。】
TypeParameterResolver
中經過resolveFieldTypes()方法、resolveReturnTypes()方法、resolveParamTypes()方法分別解析字段類型、方法返回值類型和方法參數列表中各個參數的類型。這三個方法相似。咱們就以resolveFieldTypes()來分析。TypeParameterResolve.resolveFieldTypes()
方法實現代碼以下:
public static Type resolveFieldType(Field field, Type srcType) { //獲取字段的聲明類型 Type fieldType = field.getGenericType(); //獲取字段定義所在類的Class對象 Class<?> declaringClass = field.getDeclaringClass(); //調用resolveType()方法作後續處理 return resolveType(fieldType, srcType, declaringClass); }
上述三個解析方法都會調用resolveType()會根據第一個參數Type,即方法、返回值或者方法返回參數的類型,選擇合適的方法解析。resolveType()的第二個參數表示查找該字段、返回值或者方法參數的起始位置。第三個參數則表示該字段、方法所在的類。
TypeParameterResolve.resolveType()
方法代碼以下:
private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) { if (type instanceof TypeVariable) { //解析 TypeVariable 類型 return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass); } else if (type instanceof ParameterizedType) { //解析 ParameterizedType 類型 return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass); } else if (type instanceof GenericArrayType) { //解析 GenericArrayType 類型 return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass); } else { return type; } }
TypeParameterResolve.resolveParameterizedType()
方法代碼以下:
private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) { // 獲得參數化類型中的原始類型對應的Class對象 Class<?> rawType = (Class<?>) parameterizedType.getRawType(); //返回參數化類型的類型變量 Type[] typeArgs = parameterizedType.getActualTypeArguments(); //用於保存解析後的結果 Type[] args = new Type[typeArgs.length]; for (int i = 0; i < typeArgs.length; i++) { if (typeArgs[i] instanceof TypeVariable) { //解析類型變量 args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass); } else if (typeArgs[i] instanceof ParameterizedType) { //若是嵌套了ParameterizedType則調用resolveParameterizedType()方法進行處理 args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass); } else if (typeArgs[i] instanceof WildcardType) { //若是嵌套了WildcardType則調用resolveWildcardType()方法進行處理 args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass); } else { args[i] = typeArgs[i]; } } //將解析結果封裝成TypeParameterResolver中定義的ParameterizedType實現並返回 return new ParameterizedTypeImpl(rawType, null, args); }
TypeParameterResolve.resolveTypeVar()
方法負責解析TypeVariable。具體實現以下:
private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) { Type result; Class<?> clazz; if (srcType instanceof Class) { clazz = (Class<?>) srcType; } else if (srcType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) srcType; clazz = (Class<?>) parameterizedType.getRawType(); } else { throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass()); } if (clazz == declaringClass) { //獲取上界 Type[] bounds = typeVar.getBounds(); if (bounds.length > 0) { return bounds[0]; } return Object.class; } //獲取聲明的父類類型 Type superclass = clazz.getGenericSuperclass(); //經過掃描父類進行後續解析 這個是遞歸的入口 result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass); if (result != null) { return result; } // 獲取接口 Type[] superInterfaces = clazz.getGenericInterfaces(); for (Type superInterface : superInterfaces) { //經過掃描接口進行後續解析 邏輯同掃描父類 result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface); if (result != null) { return result; } } //若在某個集成結構中解析成功則返回Object.class return Object.class; }
scanSuperTypes()方法具體實現以下:
private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) { if (superclass instanceof ParameterizedType) { ParameterizedType parentAsType = (ParameterizedType) superclass; //獲取父類的原始類型 Class<?> parentAsClass = (Class<?>) parentAsType.getRawType(); TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters(); if (srcType instanceof ParameterizedType) { //轉化父類參數化類型 parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType); } if (declaringClass == parentAsClass) { for (int i = 0; i < parentTypeVars.length; i++) { if (typeVar.equals(parentTypeVars[i])) { return parentAsType.getActualTypeArguments()[i]; } } } if (declaringClass.isAssignableFrom(parentAsClass)) { //繼續解析父類,知道解析到定義該字段的類 return resolveTypeVar(typeVar, parentAsType, declaringClass); } } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) { //聲明的父類再也不含有類型變量且不是定義該字段的類則繼續解析 return resolveTypeVar(typeVar, superclass, declaringClass); } return null; }
分析完TypeParameterResolver.resolveTypeVar()和resolveParameterizedType()兩個方法後,再來看resolveGenericArrayType()方法,該方法負責解析GenericArrayType類型的變量,它會根據數組元素的類型選擇合適的resolve *()方法進行解析,具體實現以下:
private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) { //獲取數組元素的類型 Type componentType = genericArrayType.getGenericComponentType(); Type resolvedComponentType = null; //根據數組元素類型選擇合適的方法進行解析 if (componentType instanceof TypeVariable) { resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass); } else if (componentType instanceof GenericArrayType) { //遞歸調用resolveGenericArrayType()方法 resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass); } else if (componentType instanceof ParameterizedType) { resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass); } //根絕解析後的數組項類型構造返回類型 if (resolvedComponentType instanceof Class) { return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass(); } else { return new GenericArrayTypeImpl(resolvedComponentType); } }
最後咱們來分析一下TypeParameterResolver.resolveWildcardType()
方法。該方法負責解析WildcardType類型的變量。首先解析WildcardType類型的上下界,而後經過解析後的結果構造WildcardTypeImpl對象返回。具體解析過程與上述resolve *()相似。
經過上面的方法分析咱們知道,當存在複雜的繼承關係以及泛型類型時,TypeParameterResolver能夠幫助咱們解析字段、方法和方法返回值的類型。這個是Reflector類的基礎。
MyBatis源碼中也提供了TypeParameterResolver相關的TypeParameterResolverTest這個測試類,能夠從多方面測試TypeParameterResolver的功能。咱們能夠參考一下更好的瞭解TypeParameterResolver的功能。
MyBatis中有不少模塊會使用到ObjectFactory這個接口,該接口提供了多個crate()方法的重載,經過這些方法能夠建立指定類型的對象。ObjectFactory接口定義以下:
public interface ObjectFactory { //設置配置信息 default void setProperties(Properties properties) { // NOP } //經過無參構造器建立指定類的對象 <T> T create(Class<T> type); //根據參數列表,從指定類型中選擇合適的構造器建立對象 <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs); //檢測指定類型是否爲集合類型,主要處理java.util.Collection及其子類 <T> boolean isCollection(Class<T> type); }
DefaultObjectFactory是MyBatis提供的ObjectFactory接口的惟一實現,它是一個反射工廠,其create()方法經過調用instantiateClass()方法實現。DefaultObjectFactory.instantiateClass()方法會根據傳入的參數列表選擇合適的構造函數實例化對象,具體實現以下:
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[0])); try { return constructor.newInstance(constructorArgs.toArray(new Object[0])); } catch (IllegalAccessException e) { if (Reflector.canControlMemberAccessible()) { constructor.setAccessible(true); return constructor.newInstance(constructorArgs.toArray(new Object[0])); } 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); } }
除了使用MyBatis提供的DefaultObjectFactory實現,咱們還能夠在mybatis-config.xml配置文件中指定自定義的ObjectFactory接口實現類,從而實現功能上的拓展。
下面咱們介紹反射模塊使用到的三個屬性工具類,分別是PropertyTokenizer
、PropertyNamer
和PropertyCopier
。
PropertyTokenizer中各個字段含義以下:
//當前表達式的名稱 private String name; //當前表達式的索引名 private final String indexedName; //索引下標 private String index; //子表達式 private final String children;
在PropertyTokenizer的構造函數中會對傳入的表達式進行分析,並初始化上面的屬性字段,實現以下:
public PropertyTokenizer(String fullname) { //查找"."的位置 int delim = fullname.indexOf('.'); if (delim > -1) { //初始化name name = fullname.substring(0, delim); //初始化children children = fullname.substring(delim + 1); } else { name = fullname; children = null; } //初始化indexedName indexedName = name; delim = name.indexOf('['); if (delim > -1) { //初始化index index = name.substring(delim + 1, name.length() - 1); name = name.substring(0, delim); } }
PropertyTokenizer繼承了Iterator接口,它能夠迭代處理嵌套多層表達式。PropertyTokenizer.next()會建立新的PropertyTokenizer對象並解析children字段記錄的子表達式。
PropertyNamer是另外一個工具類,將提供了下列靜態方法幫助完成方法名到屬性名的轉換,以及多種檢測操做。
public final class PropertyNamer { private PropertyNamer() { // Prevent Instantiation of Static Class } //該方法會將方法名轉換成屬性 public static String methodToProperty(String name) { if (name.startsWith("is")) { name = name.substring(2); } else if (name.startsWith("get") || name.startsWith("set")) { name = name.substring(3); } else { throw new ReflectionException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get' or 'set'."); } if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) { name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); } return name; } // 檢測是不是對應屬性名 public static boolean isProperty(String name) { return isGetter(name) || isSetter(name); } //檢測是否爲getter方法 public static boolean isGetter(String name) { return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2); } //檢測是否爲setter方法 public static boolean isSetter(String name) { return name.startsWith("set") && name.length() > 3; } }
PropertyCopier是一個屬性拷貝的工具類。其核心方法是copyBeanProperties()方法,主要實現相同類型的兩個對象之間的屬性拷貝,具體實現以下:
public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) { Class<?> parent = type; while (parent != null) { final Field[] fields = parent.getDeclaredFields(); for (Field field : fields) { try { try { field.set(destinationBean, field.get(sourceBean)); } catch (IllegalAccessException e) { if (Reflector.canControlMemberAccessible()) { field.setAccessible(true); //將sourceBean對象中的屬性設置到destinationBean對象中 field.set(destinationBean, field.get(sourceBean)); } else { throw e; } } } catch (Exception e) { // Nothing useful to do, will only fail on final fields, which will be ignored. } } // 繼續拷貝父類中的定義的字段 parent = parent.getSuperclass(); } }
MetaClass經過Reflector和PropertyTokenizer組合使用,實現了對複雜的屬性表達式的解析,並實現了獲取指定屬性信息的功能。MetaClass中各個字段的含義以下:
//用於緩存Reflector對象 private final ReflectorFactory reflectorFactory; //在建立MetaClasyos時會指定一個類,該Reflector對象會用於記錄該類相關的元數據 private final Reflector reflector;
MetaClass的構造函數會爲指定的Class建立對應的Reflector對象,並用其初始化MetaClass.reflector字段,具體代碼以下:
//MetaClass的構造方法是使用private修飾的 private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) { this.reflectorFactory = reflectorFactory; //建立Reflector對象 this.reflector = reflectorFactory.findForClass(type); } //使用靜態方法建立MetaClass對象 public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) { return new MetaClass(type, reflectorFactory); }
MetaClass中比較重要的是findProperty()方法,他是經過MetaClass.buildProperty()方法實現的,而buildProperty()方法會經過PropertyTokenizer解析更復雜的屬性表達式,具體實現以下:
public String findProperty(String name) { //委託給buildProperty()方法實現 StringBuilder prop = buildProperty(name, new StringBuilder()); return prop.length() > 0 ? prop.toString() : null; } private StringBuilder buildProperty(String name, StringBuilder builder) { //解析屬性表達式 PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { //是否有子表達式 //查找PropertyTokenizer.name對應的屬性 String propertyName = reflector.findPropertyName(prop.getName()); if (propertyName != null) { //追加屬性名 builder.append(propertyName); builder.append("."); //爲該屬性建立MataClass對象 MetaClass metaProp = metaClassForProperty(propertyName); //遞歸解析PropertyTokenizer.children字段,並將解析結果添加到builder中保存 metaProp.buildProperty(prop.getChildren(), builder); } } else { //遞歸出口 String propertyName = reflector.findPropertyName(name); if (propertyName != null) { builder.append(propertyName); } } return builder; } public MetaClass metaClassForProperty(String name) { //查找指定屬性對應的class Class<?> propType = reflector.getGetterType(name); //爲改屬性建立對應的MetaClass對象 return MetaClass.forClass(propType, reflectorFactory); }
注意:Meta.Class.findProperty()方法只查找"."導航的屬性,並無檢測下標。
MetaClass.hasGetter()
方法和MetaClass.hasSetter()
方法負責判斷屬性表達式所表示的屬性是否有對應的屬性,這兩個方法邏輯相似,咱們以hasGetter()
方法爲例子進行分析,這兩個類方法實現最終都會查找Reflector.getMethods
集合或Reflector.setMethods
集合。根據前面介紹的Reflector.addFields()
方法,當字段沒有對應的getter/setter方法時會添加相應的getFieldInvoker/setFieldInvoker
對象,因此Reflector有權限訪問指定字段的時候這兩個方法的行爲並不像其方法所暗示的那樣只直接判斷屬性的getter/setter方法,咱們來看看MetaClass.hasGetter()
方法的實現代碼:
public boolean hasGetter(String name) { //解析屬性表達式 PropertyTokenizer prop = new PropertyTokenizer(name); //存在待處理的子表達式 if (prop.hasNext()) { //PropertyTokenizer.name指定的屬性有getter方法 才能處理子表達式 if (reflector.hasGetter(prop.getName())) { //metaClassForProperty(PropertyTokenizer)是上面metaClassForProperty(String)的重載 可是邏輯有很大差別 MetaClass metaProp = metaClassForProperty(prop); //遞納入口 return metaProp.hasGetter(prop.getChildren()); } else { //遞歸出口 return false; } } else { //遞歸出口 return reflector.hasGetter(prop.getName()); } }
MetaClass.metaClassForProperty(PropertyTokenizer)方法底層會調用MetaClass.getGetterType(PropertyTokenizer)方法,針對PropertyTokenizer中是否包含索引信息進一步處理,代碼以下:
private MetaClass metaClassForProperty(PropertyTokenizer prop) { //獲取表達式標識的屬性的類型 Class<?> propType = getGetterType(prop); return MetaClass.forClass(propType, reflectorFactory); } private Class<?> getGetterType(PropertyTokenizer prop) { //獲取屬性類型 Class<?> type = reflector.getGetterType(prop.getName()); //該表達式中是否試用"[]"指定了下標,切是Collect子類 if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) { //經過TypeParameterResolver工具類解析屬性的類型 Type returnType = getGenericGetterType(prop.getName()); //針對ParameterizedType進行處理,既針對泛型類型進行處理 if (returnType instanceof ParameterizedType) { //獲取實際的類型參數 Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); if (actualTypeArguments != null && actualTypeArguments.length == 1) { //泛型的類型 returnType = actualTypeArguments[0]; if (returnType instanceof Class) { type = (Class<?>) returnType; } else if (returnType instanceof ParameterizedType) { type = (Class<?>) ((ParameterizedType) returnType).getRawType(); } } } } return type; } private Type getGenericGetterType(String propertyName) { try { //根據Reflector.getMethods集合中記錄的invoker實現類的類型,決定解析getter方法返回值類型仍是解析字段類型 Invoker invoker = reflector.getGetInvoker(propertyName); if (invoker instanceof MethodInvoker) { Field _method = MethodInvoker.class.getDeclaredField("method"); _method.setAccessible(true); Method method = (Method) _method.get(invoker); return TypeParameterResolver.resolveReturnType(method, reflector.getType()); } else if (invoker instanceof GetFieldInvoker) { Field _field = GetFieldInvoker.class.getDeclaredField("field"); _field.setAccessible(true); Field field = (Field) _field.get(invoker); return TypeParameterResolver.resolveFieldType(field, reflector.getType()); } } catch (NoSuchFieldException | IllegalAccessException ignored) { } return null; }
MetaClass中的其餘get *()
方法比較簡單,大多數直接依賴Reflector的對應方法的實現的。經過對MetaClass的分析,咱們瞭解了findProperty()
、hasGetter()
、hasSetter()
等方法的實現原理。
ObjectWrapper顧名思義就是對象的包裝類,對對象級別的元信息進行處理。ObjectWrapper接口是對對象的包裝,抽象了對象的屬性信息,它定義了一系列的查詢對屬性信息的方法,以及更新屬性的方法。
ObjectWrapper接口的定義以下:
public interface ObjectWrapper { //若是是普通bean調用getter方法 若是是集合 則獲取指定key或者下標對應的value值 Object get(PropertyTokenizer prop); //若是是普通bean調用setter方法 若是是集合 則設置指定key或者下標對應的value值 void set(PropertyTokenizer prop, Object value); //查找屬性表達式指定的屬性,第二個參數標識是否忽視屬性表達式的下劃線 String findProperty(String name, boolean useCamelCaseMapping); //查找可讀屬性的名稱集合 String[] getGetterNames(); //查找可寫屬性的名稱集合 String[] getSetterNames(); //解析表達式指定屬性的setter方法的參數類型 Class<?> getSetterType(String name); //解析表達式指定屬性的getter方法的參數類型 Class<?> getGetterType(String name); //判斷屬性表達式指定屬性是否有getter方法 boolean hasSetter(String name); //判斷屬性表達式指定屬性是否有setter方法 boolean hasGetter(String name); //爲屬性表達式指定的屬性建立相應的MetaObject對象 MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory); //封裝的對象是否爲Collect類型 boolean isCollection(); //調用Collection對象的add()方法 void add(Object element); //調用Collection對象的addAll()方法 <E> void addAll(List<E> element); }
ObjectWrapperFactory負責建立ObjectWrapper對象,關係如圖所示:
DefaultObjectWrapperFactory實現了ObjectWrapperFactory接口,但它實現的getWrapperFor()方法始終拋出異常,hasWrapperFor()方法始終返回false,因此該實現方法其實是不可用的。可是與ObjectFactory相似,咱們能夠在mybatis-config.xml配置自定義的ObjectWrapperFactory實現類進行拓展。
BaseWrapper是一個實現了ObjectWrapper接口的抽象類,其中封裝了MetaObject對象,並提供了三個經常使用的方法供其子類使用。如圖所示:
BaseWrapper.resolveCollection()方法會調用MetaObject.getValue()方法,它會解析屬性表達式並獲取指定的屬性,MetaObject.getValue()方法的實如今下面介紹。
BaseWrapper.getCollectionValue()方法和setCollectionValue()方法會解析屬性表達式的索引信息,而後獲取或設置對應項。這兩個方法相似。在這裏咱們只分析一下getCollectionValue()方法。
protected Object getCollectionValue(PropertyTokenizer prop, Object collection) { if (collection instanceof Map) { //若是是map類型則index爲key return ((Map) collection).get(prop.getIndex()); } else { //若是是其餘類型則index爲下標 int i = Integer.parseInt(prop.getIndex()); if (collection instanceof List) { return ((List) collection).get(i); } else if (collection instanceof Object[]) { return ((Object[]) collection)[i]; } else if (collection instanceof char[]) { return ((char[]) collection)[i]; } else if (collection instanceof boolean[]) { return ((boolean[]) collection)[i]; } else if (collection instanceof byte[]) { return ((byte[]) collection)[i]; } else if (collection instanceof double[]) { return ((double[]) collection)[i]; } else if (collection instanceof float[]) { return ((float[]) collection)[i]; } else if (collection instanceof int[]) { return ((int[]) collection)[i]; } else if (collection instanceof long[]) { return ((long[]) collection)[i]; } else if (collection instanceof short[]) { return ((short[]) collection)[i]; } else { throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array."); } } }
BeanWrapper繼承了BaseWrapper抽象類,其中封裝了一個JavaBean對象以及該JavaBean相應的MetaClass對象,固然還有從BaseWrapper繼承下來的、該JavaBean對象相應的MetaObject對象。
BeanWrapper.get()方法和set()方法會根據指定的屬性表達式,獲取或者設置相應的屬性值,二者邏輯類似,這裏咱們以get()方法分析,具體代碼以下:
public Object get(PropertyTokenizer prop) { //存在索引信息 則表示屬性表達式中的name部分爲集合類型 if (prop.getIndex() != null) { //經過MetaObject.getValue()方法獲取object對象中指定集合屬性 Object collection = resolveCollection(prop, object); //獲取集合元素 return getCollectionValue(prop, collection); } else { //不存在索引信息 則name部分爲普通對象,查找並調用invoker相關方法獲取屬性 return getBeanProperty(prop, object); } } private Object getBeanProperty(PropertyTokenizer prop, Object object) { try { //根據屬性名稱查找Reflector.getMethods集合中相應的getFieldInvoker或者MethodInvoker Invoker method = metaClass.getGetInvoker(prop.getName()); try { //獲取屬性值 return method.invoke(object, NO_ARGUMENTS); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } catch (RuntimeException e) { throw e; } catch (Throwable t) { throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t); } }
CollectionWrapper實現了ObjectWrapper接口,其中封裝了Collection< Object >類型的對象,可是它大部分實現方法都會拋出UnsupportedOperationException異常。
MapWrapper是BaseWrapper的另外一個實現類,其中封裝了Map<String,Object>類型對象,咱們瞭解了MetaObject和BeanWrapper實現後,垂手可得就能看懂MapWrapper的實現代碼。
MetaObject提供了獲取/設置對象中指定的屬性值、檢測getter/setter等經常使用功能,可是ObjectWrapper只是這些功能的最後一站,咱們省略了對屬性表達式解析過程的介紹,而該解析過程就是在MetaObject中實現的。
MetaObject中字段的含義以下:
//原始JavaBean對象 private final Object originalObject; //封裝了originalObject對象 private final ObjectWrapper objectWrapper; //負責實例化originalObject的工廠對象 private final ObjectFactory objectFactory; //負責建立ObjectWrapper的工廠對象 private final ObjectWrapperFactory objectWrapperFactory; //用於建立並緩存Reflector對象的工廠對象 private final ReflectorFactory reflectorFactory;
MetaObject的構造方法會根據傳入的原始對象的類型以及ObjectFactory工廠的實現建立相應的ObjectWrapper對象,代碼以下:
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { //初始化上述字段 this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; this.reflectorFactory = reflectorFactory; //若原始對象已是ObjectWrapper對象則直接使用 if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { //若objectWrapperFactory可以爲該原始兌現建立對應的ObjectWrapper對象則由優先使用objectWrapperFactory, //而DefaultObjectWrapperFactory.hasWrapperFor()始終返回false,用戶能夠自定義ObjectWrapperFactory實現進行拓展 this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { //若原始對象是map類型 則建立MapWrapper對象 this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { //若原始對象是Collection類型 則建立CollectionWrapper對象 this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { //若對象是普通的JavaBean對象,則建立BeanWrapper對象 this.objectWrapper = new BeanWrapper(this, object); } } //Meta的構造方法是private的 只能靠forObject()這個靜態方法來建立MetaObject對象 public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) { if (object == null) { //若原始對象爲空 則統一返回SystemMetaObject.NULL_META_OBJECT這個靜態對象 return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory); } }
MetaObject和ObjectWrapper中關於類級別的方法,例如hasGetter()、hasSetter()、findProperty()等方法,都是直接調用MetaClass的對應方法實現的。其餘方法都是關於對象級別的方法,這些方法都是與ObjectWrapper配合實現,例如MetaObject.getValue()/setValue()方法,這裏以getValue()方法爲例進行分析,具體代碼以下:
public Object getValue(String name) { //解析屬性表達式 PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { //處理子表達式 //根據PropertyTokenizer解析後製定的屬性 建立相應的MetaObject對象 MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { //遞歸處理子表達式 return metaValue.getValue(prop.getChildren()); } } else { //經過ObjectWrapper獲取指定的屬性值 return objectWrapper.get(prop); } } public MetaObject metaObjectForProperty(String name) { //獲取指定的屬性 Object value = getValue(name); //建立該屬性對象相應的MetaObject對象 return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory); }
ObjectWrapper.instantiateProperty()方法實際上就是調用ObjectFactory接口的create()方法(默認實現是DefaultObjectFactory)建立對象並將其設置到所屬的對象中,這裏咱們看下具體的實現代碼:
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) { MetaObject metaValue; //獲取屬性相應的setter方法的參數類型 Class<?> type = getSetterType(prop.getName()); try { //經過反射的方式建立對象 Object newObject = objectFactory.create(type); metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory()); //將上面建立的屬性對象 設置到對應的屬性對象集合中 set(prop, newObject); } catch (Exception e) { throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e); } return metaValue; }
理解了MetaObject和BeanWrapper如何經過遞歸的方式處理屬性表達式指定的屬性值後,其餘方法的實現原理就好理解了。例如getGetterType()、getSetterType()、hasGetter()、hasSetter()等方法,都是先遞歸處理屬性表達式,而後調用MetaClass相應的方法實現的。
本文由 Janker 創做,採用 CC BY 3.0 CN協議 進行許可。 可自由轉載、引用,但需署名做者且註明文章出處。如轉載至微信公衆號,請在文末添加做者公衆號二維碼。