*声明,本文章的参考
Mybatis 3.5.19 源码
技术文章摘抄-深入剖析 MyBatis 核心原理-完
Relefctor
MyBatis 为了降低反射的使用门槛,封了一个反射专用的工具包,位与 org.apache.ibatis.reflectio 中。
这个包中有一个非常重要的实现类 Relefctor ,他记录了一个 type 应对的所有反射可以得到的信息:

而获取这些信息的逻辑都被放到 Reflector(Type type) 的构造方法中:
public Reflector(Type type) {
// 将原始类型做备份
this.type = type;
if (type instanceof ParameterizedType) {
// 如果是一个参数化的类型(泛型),值获取他的原始类型(避免泛型擦除带来的影响)
this.clazz = (Class<?>) ((ParameterizedType) type).getRawType();
} else {
// 否则直接将类型转换为Class
this.clazz = (Class<?>) type;
}
// 通过反射获取默认构造器并保存
addDefaultConstructor(clazz);
// 获取类的所有方法(包括私有方法)并保存
Method[] classMethods = getClassMethods(clazz);
if (isRecord(clazz)) {
// 如果是一个Record类,只处理getter方法即可
addRecordGetMethods(classMethods);
} else {
// 获取普通 pojo 的 getter 、 setter 方法和字段
addGetMethods(classMethods);
addSetMethods(classMethods);
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);
}
}Java其中的两个 if 线代表了两个特殊情况:参数化对象和 Record 对象。
在 getClassMethods 方法中,进行了一个递归的操作,从下往上寻找最新的方法实现,之类没有实现的话,就用父类的:
private Method[] getClassMethods(Class<?> clazz) {
Map<String, Method> uniqueMethods = new HashMap<>();
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
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 类为止
currentClass = currentClass.getSuperclass();
}
Collection<Method> methods = uniqueMethods.values();
return methods.toArray(new Method[0]);
}
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
for (Method currentMethod : methods) {
if (!currentMethod.isBridge()) {
// 根据方法生成自己的签名
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);
}
}
}
}
// 生成签名的方法
private String getSignature(Method method) {
StringBuilder sb = new StringBuilder();
Class<?> returnType = method.getReturnType();
// 返回值类型+#
sb.append(returnType.getName()).append('#');
// 方法名
sb.append(method.getName());
Class<?>[] parameters = method.getParameterTypes();
// :参数名,参数名
for (int i = 0; i < parameters.length; i++) {
sb.append(i == 0 ? ':' : ',').append(parameters[i].getName());
}
return sb.toString();
}Java由于记录了签名中包含了详细的参数名,所以也不会将重载的方法给混在一起。
得到所有的方法后,还需要区分去其中的 getter 和 setter 方法,addGetMethods:
private void addGetMethods(Method[] methods) {
Map<String, List<Method>> conflictingGetters = new HashMap<>();
/**
* 1. 过滤出所有的 getter 方法(参数个数为0,方法名以 get 或 is 开头)
* 2. mothodToProerty 剥离方法名的 get/is 前缀,并将首字母小写,得到属性名
* 3. 将属性名和方法列表添加到冲突的 getter 方法列表中
* 3.1 为什么要有冲突的 getter 方法列表? a. 子类在重新父类的 getter 方法时,可能会改变返回值类型(协变返回类型),导致父类和子类的 getter 方法存在冲突; b. Record 类中,所有的组件方法都是 getter 方法,且方法名与属性名相同,也会导致冲突 c. Boolean 类型的 getter 方法可能存在 getXxx 和 isXxx 两种形式,也会导致冲突
*/
Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
.forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
// 解决 getter 方法的冲突,确定最终的 getter 方法,并将其添加到 getMethods 和 getTypes 中
resolveGetterConflicts(conflictingGetters);
}
// 看一下用于获取属性名字的 mothodToProperty 方法:
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;
}
// 真正用于解决冲突的 resolveGetterConflicts 方法:
private void resolveGetterConflicts(Map<String, List<Method>> 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;
}
// 比较两个方法的返回值类型,并选择实现上更加具体的那个作为 winner,如果两个方法的返回值类型不兼容,则将 isAmbiguous 设置为 true,表示存在歧义
Class<?> winnerType = winner.getReturnType();
Class<?> candidateType = candidate.getReturnType();
if (candidateType.equals(winnerType)) {
if (!boolean.class.equals(candidateType)) {
isAmbiguous = true;
break;
}
if (candidate.getName().startsWith("is")) {
winner = candidate;
}
} else if (candidateType.isAssignableFrom(winnerType)) {
// OK getter type is descendant
} else if (winnerType.isAssignableFrom(candidateType)) {
winner = candidate;
} else {
isAmbiguous = true;
break;
}
}
// 创建并添加对应方法的 invoke 对象,并将方法的返回值类型保存到 getTypes 中
addGetMethod(propName, winner, isAmbiguous);
}
}
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);
getMethods.put(name, invoker);
Type returnType = TypeParameterResolver.resolveReturnType(method, type);
getTypes.put(name, Map.entry(returnType, typeToClass(returnType)));
}Java与 addGetMothods 方法不同的是, addsetMothods 方法解决冲突是直接获取到 getMothods 对应的字段的 getter 方法的返回值类型,然后做匹配。
Invoker
在上面的 addGetMethod 方法中,我们可以看到一个 MethodInvoker 的类,这是 MyBatis 为了方便调用 Invoke 又针对方法和字段写了工具类:

看一看 MethodInvoker 都帮我们做了什么:
public class MethodInvoker implements Invoker {
private final Class<?> type;
private final Method method;
public MethodInvoker(Method method) {
this.method = method;
if (method.getParameterTypes().length == 1) {
type = method.getParameterTypes()[0];
} else {
type = method.getReturnType();
}
}
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
try {
return method.invoke(target, args);
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
method.setAccessible(true);
return method.invoke(target, args);
}
throw e;
}
}
@Override
public Class<?> getType() {
return type;
}
}
Java可以看到,在 invoke 方法中,先尝试直接调用 invoke 一次,如果失败了就添加私有方法的访问权限再试一次,否则就报错,也就是说这个包装方法可以自动帮我们处理静态方法(其实在另外两个 GetfieldInvoker 和 SetfieldInvoker 中也是一样的处理方式)。
而 AmbiguousMethodInvoker 要更加的特殊,直接抛出异常:
public class AmbiguousMethodInvoker extends MethodInvoker {
private final String exceptionMessage;
public AmbiguousMethodInvoker(Method method, String exceptionMessage) {
super(method);
this.exceptionMessage = exceptionMessage;
}
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
throw new ReflectionException(exceptionMessage);
}
}JavaObjtctFactory

Objectfactory 接口提供了根据 class 类和构造器参数去创建对象实例的功能,在执行完 SQL 语句将结果向 Java 对象进行转换时就经常需要用到这个他的默认实现 DefaultObjectFactory ,其核心实现:
if(constructorArgTypes == null || constructorArgs == null){
constructor = type.getDeclaredConstructor();
return construtor.newInstance();
}else{
constructor = type.getDeclardConstructor(constructorArgTypes.toArray(new Class[0]));
return contructor.newInstance(constructorArgs.toArray(new object[0]));
}Java当然源码中的代码会更加的健壮。
ReflectorFactory

ReflectorFactory 不仅为我们提供了创建 Reflector 的能力,还通过一个内置的 reflectorMap 为我们缓存起来了创建过的 Reflector ,我们可以通过 setClassCacheEnable 来设置是否开支缓存,默认为开启:
@Override
public Reflector findForClass(Type type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
return reflectorMap.computeIfAbsent(type, Reflector::new);
}
return new Reflector(type);
}JavaPropertyUtils

在 property 包下提供了三个相对独立的静态类,分别有不同的作用:
- PropertyTokenizer
对由./[]构成的字符串表达式进行解析。解析带.的表达式时,可以通过迭代器遍历整个表达式,其中 name 表示当前两个 . 之前的字符,children 是未遍历的字符串。
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
private String name;
private final String indexedName;
private String index;
private final String children;
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
@Override
public boolean hasNext() {
return children != null;
}
@Override
public PropertyTokenizer next() {
return new PropertyTokenizer(children);
}
@Override
public void remove() {
throw new UnsupportedOperationException(
"Remove is not supported, as it has no meaning in the context of properties.");
}
}
Java- Propertynamer
主要是对参数名称进行处理,其中的methodToProperty上面已经用到了,就是推断方法对应的源参数,另外的还有:是否是 getter / setter。
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);
}
public static boolean isGetter(String name) {
return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2;
}
public static boolean isSetter(String name) {
return name.startsWith("set") && name.length() > 3;
}
}Java- PropertCopier
通过反射的方式对 javaBean 的属性进行复制
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()) {
throw e;
}
field.setAccessible(true);
field.set(destinationBean, field.get(sourceBean));
}
} catch (Exception e) {
// Nothing useful to do, will only fail on final fields, which will be ignored.
}
}
parent = parent.getSuperclass();
}
}
JavaMetaClass
MetaClass 提供了获取类中属性描述信息的功能,底层依赖重要的 Reflector,在 MetaClass 的构造方法中会将传入的 Class 封装成一个 Reflector 对象,并记录到 reflector 字段中,MetaClass 的后续属性查找都会使用到该 Reflector 对象。
这个类主要是提供一些类级别的工具,比如 是否有 setter ,setter / getter 的名字,getter 的返回类型等等。
同时 MetaClass 中的方法大量依赖的 PropertyTokenizer 的迭代器模式。
MetaObject & ObjectWrapper
上面的 ObjectFactory 为类型转换提供了类型构造的能力,而这两个类则是提供了赋值和获取值的能力。

MetaObject 是其他方法调用的入口,常用的方法有三个
- 获取 MetaObject对象的静态方法:static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory)
- 获取值:Object getValue(String name)
- 修改值:void setValue(String name, Object value)
forObject :
public static MetaObject forObject(Object object, ObjectFactory objectFactory,
ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
if (object == null) {
return SystemMetaObject.NULL_META_OBJECT;
}
return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
ReflectorFactory reflectorFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) {
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else {
this.objectWrapper = new BeanWrapper(this, object);
}
}Java从上面的构造方法可以看出,创建 MetaObject 时会跟根据不同的条件,创建不同的 Wrapper ,Wrapper 间的关系如下:

以 metaObject 中的 objectwrapper 是 BeseWrapper 为例,可以看一下调用 getVlaue 方法时的时序图:
sequenceDiagram
autonumber
actor Caller as 调用方
participant MetaObject as MetaObject
participant PropertyTokenizer as PropertyTokenizer
participant Wrapper as ObjectWrapper (具体实现类)
participant BaseWrapper as BaseWrapper (抽象父类)
participant MetaValue as MetaObject (子属性的MetaObject)
Caller->>MetaObject: getValue(name)
activate MetaObject
MetaObject->>PropertyTokenizer: new PropertyTokenizer(name)
activate PropertyTokenizer
Note right of PropertyTokenizer: 解析属性名,拆解出当前名称(name)、<br>索引(index)和子属性(children)
PropertyTokenizer-->>MetaObject: prop
deactivate PropertyTokenizer
MetaObject->>Wrapper: get(prop)
activate Wrapper
alt prop.hasNext() (存在子属性,如 "user.name")
Wrapper->>BaseWrapper: getChildValue(prop)
activate BaseWrapper
BaseWrapper->>MetaObject: metaObjectForProperty(prop.getIndexedName())
activate MetaObject
Note right of MetaObject: 内部获取当前属性值,<br>并包装为新的 MetaObject 返回
MetaObject-->>BaseWrapper: metaValue
deactivate MetaObject
alt metaValue == SystemMetaObject.NULL_META_OBJECT
BaseWrapper-->>Wrapper: null
else metaValue 有效
BaseWrapper->>MetaValue: getValue(prop.getChildren())
activate MetaValue
Note right of MetaValue: 递归调用子 MetaObject <br>去解析剩余的属性路径
MetaValue-->>BaseWrapper: value
deactivate MetaValue
BaseWrapper-->>Wrapper: value
end
deactivate BaseWrapper
else !prop.hasNext() (无子属性,说明是最后一层)
alt prop.getIndex() != null (具有索引,如 "orders[0]")
Wrapper->>BaseWrapper: resolveCollection(prop, object)
activate BaseWrapper
Note right of BaseWrapper: 确定当前集合对象
BaseWrapper-->>Wrapper: collection
deactivate BaseWrapper
Wrapper->>BaseWrapper: getCollectionValue(prop, collection)
activate BaseWrapper
Note right of BaseWrapper: 判断是 Map, List 还是 Array,<br>根据 prop.getIndex() 提取对应的元素值
BaseWrapper-->>Wrapper: value
deactivate BaseWrapper
else 没有索引 (普通单一属性,如 "age")
Note right of Wrapper: 例如 BeanWrapper 会通过反射<br>直接调用 getter 方法获取值
Wrapper->>Wrapper: 通过反射/Map的Get获取最终值
end
end
Wrapper-->>MetaObject: 返回获取到的属性值
deactivate Wrapper
MetaObject-->>Caller: 返回获取到的属性值
deactivate MetaObject
Comments NOTHING