标签:iter builder and UNC extend ocr 简单 type continue
本文,我们来分享 MyBatis 的反射模块,对应 reflection
包。如下图所示:
parsing
包来说,reflection
包的代码量大概是 2-3 倍。当然,不要慌,都是比较简单的代码。在 《精尽 MyBatis 源码解析 —— 项目结构一览》 中,简单介绍了这个模块如下:
Java 中的反射虽然功能强大,但对大多数开发人员来说,写出高质量的反射代码还是 有一定难度的。MyBatis 中专门提供了反射模块,该模块对 Java 原生的反射进行了良好的封装,提了更加简洁易用的 API,方便上层使调用,并且对反射操作进行了一系列优化,例如缓存了类的元数据,提高了反射操作的性能。
下面,我们就来看看具体的源码。因为 reflection
是基础支持层,所以建议胖友在我们讲解到的类和方法中,打折断点一起来了解。
org.apache.ibatis.reflection.Reflector
,反射器,每个 Reflector 对应一个类。Reflector 会缓存反射操作需要的类的信息,例如:构造方法、属性名、setting / getting 方法等等。代码如下:
// Reflector.java
|
type
属性,每个 Reflector 对应的类。defaultConstructor
属性,默认无参构造方法。在 <1>
处初始化,详细解析,见 「2.1 addDefaultConstructor」 。getMethods
、getTypes
属性,分别为属性对应的 getting 方法、getting 方法的返回类型的映射。在 <2>
处初始化,详细解析,见 「2.2 addGetMethods」 。setMethods
、setTypes
属性,分别为属性对应的 setting 方法、setting 方法的参数类型的映射。在 <3>
处初始化,详细解析,见 「2.3 addSetMethods」 。<4>
处,初始化 getMethods
+ getTypes
和 setMethods
+ setTypes
,通过遍历 fields 属性。详细解析,见 「2.4 addFields」 。<5>
处,初始化 readablePropertyNames
、writeablePropertyNames
、caseInsensitivePropertyMap
属性。#addDefaultConstructor(Class<?> clazz)
方法,查找默认无参构造方法。代码如下:
// Reflector.java
|
#addGetMethods(Class<?> cls)
方法,初始化 getMethods
和 getTypes
,通过遍历 getting 方法。代码如下:
// Reflector.java
|
<1>
处,conflictingGetters
变量,属性与其 getting 方法的映射。因为父类和子类都可能定义了相同属性的 getting 方法,所以 VALUE
会是个数组。<2>
处,调用 #getClassMethods(Class<?> cls)
方法,获得所有方法。详细解析,见 「2.2.1 getClassMethods」 。<3>
处,遍历所有方法,挑选符合的 getting 方法,添加到 conflictingGetters
中。
<3.1>
处,方法参数大于 0 ,说明不是 getting 方法,忽略。
<3.2>
处,方法名以 get 和 is 方法名开头,说明是 getting 方法。
<3.3>
处,调用 PropertyNamer#methodToProperty(String name)
方法,获得属性名。详细解析,见 「6.3 PropertyNamer」 。
<3.4>
处,调用 #addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method)
方法,添加到 conflictingGetters
中。代码如下:
// Reflector.java
|
<4>
处,调用 #resolveGetterConflicts(Map<String, List<Method>>)
方法,解决 getting 冲突方法。详细解析,见 「2.2.2 resolveGetterConflicts」 。#getClassMethods(Class<?> cls)
方法,获得所有方法。代码如下:
// Reflector.java
|
代码比较简单,胖友自己看注释。
<1>
和 <2>
处,会调用 #addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods)
方法,添加方法数组到 uniqueMethods
中。代码如下:
// Reflector.java
|
<3>
处,会调用 #getSignature(Method method)
方法,获得方法签名。代码如下:
// Reflector.java
|
returnType#方法名:参数名1,参数名2,参数名3
。void#checkPackageAccess:java.lang.ClassLoader,boolean
。#resolveGetterConflicts(Map<String, List<Method>>)
方法,解决 getting 冲突方法。最终,一个属性,只保留一个对应的方法。代码如下:
// Reflector.java
|
总体比较简单,胖友自己瞅瞅。我们只说两个关键点哈。
<1>
处,基于返回类型比较。重点在 <1.1>
和 <1.2>
的情况,因为子类可以修改放大返回值,所以在出现这个情况时,选择子类的该方法。例如,父类的一个方法的返回值为 List ,子类对该方法的返回值可以覆写为 ArrayList 。代码如下:
public class A {
|
<2>
处,调用 #addGetMethod(String name, Method method)
方法,添加方法到 getMethods
和 getTypes
中。代码如下:
// Reflector.java
|
<2.1>
处,调用 #isValidPropertyName(String name)
方法,判断是合理的属性名。代码如下:
// Reflector.java
|
<2.2>
处,添加到 getMethods
中。此处,我们可以看到一个 MethodInvoker 类,详细解析,见 「4.3 MethodInvoker」 。
<2.3>
处,添加到 getTypes
中。
此处,我们可以看到一个 TypeParameterResolver 类,详细解析,见 「14. TypeParameterResolver」 。
#typeToClass(Type src)
方法,获得 java.lang.reflect.Type
对应的类。代码如下:
// Reflector.java
|
#addSetMethods(Class<?> cls)
方法,初始化 setMethods
和 setTypes
,通过遍历 setting 方法。代码如下:
// Reflector.java
|
#addGetMethods(Class<?> cls)
方法差不多。主要差异点在 <1>
和 <2>
处。因为 <1>
一眼就能明白,所以我们只看 <2>
,调用 #resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)
方法,解决 setting 冲突方法。详细解析,见 「2.3.1 resolveSetterConflicts」 中。#resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)
方法,解决 setting 冲突方法。代码如下:
// Reflector.java
|
总体比较简单,胖友自己瞅瞅。我们只说两个关键点哈。
<1>
处,解决冲突 setting 方法的方式,实际和 getting 方法的方式是不太一样的。首先,多的就是考虑了对应的 getterType
为优先级最高。其次,#pickBetterSetter(Method setter1, Method setter2, String property)
方法,选择一个更加匹配的,和 getting 方法是相同的,因为要选择精准的方法。代码如下:
// Reflector.java
|
<2>
处,调用 #addSetMethod(String name, Method method)
方法,添加到 setMethods
和 setTypes
中。代码如下:
// Reflector.java
|
#addGetMethod(String name, Method method)
方法是类似的。#addFields(Class<?> clazz)
方法,初始化 getMethods
+ getTypes
和 setMethods
+ setTypes
,通过遍历 fields 属性。实际上,它是 #addGetMethods(...)
和 #addSetMethods(...)
方法的补充,因为有些 field ,不存在对应的 setting 或 getting 方法,所以直接使用对应的 field ,而不是方法。代码如下:
// Reflector.java
|
<1>
处,若 setMethods
不存在,则调用 #addSetField(Field field)
方法,添加到 setMethods
和 setTypes
中。代码如下:
// Reflector.java
|
<2>
处,若 getMethods
不存在,则调用 #addGetField(Field field)
方法,添加到 getMethods
和 getTypes
中。代码如下:
// Reflector.java
|
Reflector 中,还有其它方法,用于对它的属性进行访问。比较简单,感兴趣的胖友,自己来瞅瞅。例如:
// Reflector.java
|
org.apache.ibatis.reflection.ReflectorFactory
,Reflector 工厂接口,用于创建和缓存 Reflector 对象。代码如下:
// ReflectorFactory.java
|
org.apache.ibatis.reflection.DefaultReflectorFactory
,实现 ReflectorFactory 接口,默认的 ReflectorFactory 实现类。代码如下:
// DefaultReflectorFactory.java
|
org.apache.ibatis.reflection.invoker.Invoker
,调用者接口。代码如下:
// Invoker.java
|
#invoke(Object target, Object[] args)
方法,执行一次调用。而具体调用什么方法,由子类来实现。org.apache.ibatis.reflection.invoker.GetFieldInvoker
,实现 Invoker 接口,获得 Field 调用者。代码如下:
// GetFieldInvoker.java
|
org.apache.ibatis.reflection.invoker.SetFieldInvoker
,实现 Invoker 接口,设置 Field 调用者。代码如下:
// SetFieldInvoker.java
|
org.apache.ibatis.reflection.invoker.MethodInvoker
,实现 Invoker 接口,指定方法的调用器。代码如下:
// MethodInvoker.java
|
org.apache.ibatis.reflection.factory.ObjectFactory
,Object 工厂接口,用于创建指定类的对象。代码如下:
// ObjectFactory.java
|
org.apache.ibatis.reflection.factory.DefaultObjectFactory
,实现 ObjectFactory、Serializable 接口,默认 ObjectFactory 实现类。
#create(Class<T> type, ...)
方法,创建指定类的对象。代码如下:
// DefaultObjectFactory.java
|
<1>
处,调用 #resolveInterface(Class<?> type)
方法,获得需要创建的类。代码如下:
// DefaultObjectFactory.java
|
<1>
处,调用 #instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
方法,创建指定类的对象。代码如下:
// DefaultObjectFactory.java
|
<x1>
、<x2>
两种情况。#isCollection(Class<T> type)
方法,判断指定类是否为集合类。代码如下:
// DefaultObjectFactory.java
|
java.util.Collection
的子类。#setProperties(Properties properties)
方法,设置 Properties 。代码如下:
// DefaultObjectFactory.java
|
org.apache.ibatis.reflection.property
包下,提供了 PropertyCopier、PropertyNamer、PropertyTokenizer 三个属性相关的工具类。接下来,我们逐小节来解析。
org.apache.ibatis.reflection.property.PropertyCopier
,属性复制器。代码如下:
// PropertyNamer.java
|
org.apache.ibatis.reflection.property.PropertyNamer
,属性名相关的工具类方法。代码如下:
public final class PropertyNamer {
|
org.apache.ibatis.reflection.property.PropertyTokenizer
,实现 Iterator 接口,属性分词器,支持迭代器的访问方式。
举个例子,在访问 "order[0].item[0].name"
时,我们希望拆分成 "order[0]"
、"item[0]"
、"name"
三段,那么就可以通过 PropertyTokenizer 来实现。
// PropertyTokenizer.java
|
name
属性,当前字符串。children
属性,剩余字符串。<1>
处,初始化 name
、children
字符串,使用 ‘.‘
作为分隔。indexedName
属性,索引的 name
属性,因为 name
如果存在 index
会被更改。<2>
处,记录当前 name
。index
属性,编号。分成两种情况:
name
为数组 item[0]
时,则 index
为 "0"
。name
为 Map map[key]
时,则 index
为 "key"
。<3>
处,初始化 index
,并修改 name
字符串,使用 ‘[‘
作为分隔符。#next()
方法,迭代获得下一个 PropertyTokenizer 对象。代码如下:
// PropertyTokenizer.java
|
#hasNext()
方法,判断是否有下一个元素。代码如下:
// PropertyTokenizer.java
|
PropertyTokenizer 中,还有其它方法,比较简单,感兴趣的胖友,自己来瞅瞅。
org.apache.ibatis.reflection.MetaClass
,类的元数据,基于 Reflector 和 PropertyTokenizer ,提供对指定类的各种骚操作。
// MetaClass.java
|
目前有两个方法会涉及到调用该构造方法:
① #forClass(Class<?> type, ReflectorFactory reflectorFactory)
静态方法,创建指定类的 MetaClass 对象。代码如下:
// MetaClass.java
|
② #metaClassForProperty(String name)
方法,创建类的指定属性的类的 MetaClass 对象。代码如下:
// MetaClass.java
|
#findProperty(String name, boolean useCamelCaseMapping)
方法,根据表达式,获得属性。代码如下:
// MetaClass.java
|
useCamelCaseMapping
属性,是否要下划线转驼峰 。但是,在 <1>
处,我们仅仅看到 _
被替换成了空串。这是为什么呢?继续往下看。
<2>
处,调用 #findProperty(String name)
方法,根据表达式,获得属性。代码如下:
// MetaClass.java
|
<3>
处,调用 #buildProperty(String name, StringBuilder builder)
方法,构建属性。代码如下:
// MetaClass.java
|
* 创建 PropertyTokenizer 对象,对 `name` 进行**分词**。当有子表达式,继续递归调用 `#buildProperty(String name, StringBuilder builder)` 方法,并将结果添加到 `builder` 中;否则,结束,直接添加到 `builder` 中。 * 在两个 `<4>` 处,解决“下划线转驼峰”的关键是,通过 `Reflector.caseInsensitivePropertyMap` 属性,忽略大小写。代码如下:
// Reflector.java
|
* x
如果胖友,你有点懵逼,可以运行下 MetaClassTest#shouldFindPropertyName()
这个单元测试方法。
#hasGetter(String name)
方法,判断指定属性是否有 getting 方法。代码如下:
// MetaClass.java
|
思路和 #findProperty((String name, ...)
方法是一样的,所以胖友自己看下。
<1>
处,调用 #metaClassForProperty(PropertyTokenizer prop)
方法,创建 创建 MetaClass 对象。代码如下:
// MetaClass.java
|
metaClassForProperty => getGetterType => getGenericGetterType
。另外,#hasSetter(String name)
方法,判断指定属性是否有 setting 方法。逻辑上,和 #hasGetter(String name)
方法类似,胖友可以自己瞅瞅。
#getGetterType(String name)
方法,获得指定属性的 getting 方法的返回值的类型。代码如下:
// MetaClass.java
|
#hasGetter(String name)
方法类似,胖友可以自己瞅瞅。另外,#getSetterType(String name)
方法,判断指定属性是否有 setting 方法。逻辑上,和 #getGetterType(String name)
方法类似,胖友可以自己瞅瞅。
MetaClass 还有其它方法,比较简单,是基于 Reflector 方法的封装,感兴趣的胖友,可以自己看看。
org.apache.ibatis.reflection.wrapper.ObjectWrapper
,对象包装器接口,基于 MetaClass 工具类,定义对指定对象的各种操作。或者可以说,ObjectWrapper 是 MetaClass 的指定类的具象化。代码如下:
// ObjectWrapper.java
|
ObjectWrapper 的子类实现如下图:
org.apache.ibatis.reflection.wrapper.BaseWrapper
,实现 ObjectWrapper 接口,ObjectWrapper 抽象类,为子类 BeanWrapper 和 MapWrapper 提供属性值的获取和设置的公用方法。代码如下:
// BaseWrapper.java |