引言
在这篇文章之中,我们会详细介绍一下MyBatis中反射工具类的详细设计。
开始
在 MyBatis 中,反射工具类主要用于高效操作 Java 对象的属性、方法和类型信息,其核心目标是支持动态 SQL 参数绑定和结果集映射。以下是 MyBatis 反射工具类的核心实现及其原理的详细说明:
反射工具类的组成
MyBatis 的反射模块主要包含以下核心类:
核心实现原理
1. Reflector:反射元信息缓存
Reflector
是反射工具的核心,预先解析并缓存类的元信息,避免每次反射操作重复解析。
关键源码解析
java
public class Reflector {
private final Class<?> type;
// 缓存属性名与对应的 Getter/Setter 方法
private final Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
private final Map<String, Invoker> setMethods = new HashMap<>();
private final Map<String, Invoker> getMethods = new HashMap<>();
private final Map<String, Class<?>> getTypes = new HashMap<>();
private final Map<String, Class<?>> setTypes = new HashMap<>();
public Reflector(Class<?> clazz) {
this.type = clazz;
// 解析类的所有方法,提取 Getter/Setter
addMethods(clazz);
addFields(clazz); // 处理没有 Getter/Setter 的公共字段
}
// 根据属性名获取 Getter 方法
public Invoker getGetInvoker(String propertyName) {
return getMethods.get(propertyName);
}
// 根据属性名获取 Setter 方法
public Invoker getSetInvoker(String propertyName) {
return setMethods.get(propertyName);
}
}
核心逻辑:
缓存优化:在类加载时解析所有
Getter
/Setter
方法,并缓存方法对象(Method
),避免频繁调用Class.getMethod()
。字段回退:如果属性没有对应的
Getter
/Setter
,直接通过公共字段(Field
)访问。大小写不敏感:属性名匹配时忽略大小写(如
userName
和username
视为同一属性)。
2. MetaObject:动态属性操作
MetaObject
是反射操作的入口,封装了对复杂对象属性的链式访问(如 user.address.city
)。
关键源码解析
java
public class MetaObject {
private final Object originalObject;
private final ObjectWrapper objectWrapper;
private final ReflectorFactory reflectorFactory;
public static MetaObject forObject(Object object, ReflectorFactory factory) {
if (object == null) {
return SystemMetaObject.NULL_META_OBJECT;
} else {
return new MetaObject(object, factory);
}
}
// 获取嵌套属性值
public Object getValue(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
return metaValue.getValue(prop.getChildren());
} else {
return objectWrapper.get(prop);
}
}
// 设置嵌套属性值
public void setValue(String name, Object value) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
metaValue.setValue(prop.getChildren(), value);
} else {
objectWrapper.set(prop, value);
}
}
}
核心逻辑:
链式属性解析:通过
PropertyTokenizer
解析形如user.address[0].city
的表达式。递归访问:逐层调用
getValue
/setValue
,直到找到最终属性。对象包装:通过
ObjectWrapper
统一处理Map
、Collection
和普通 JavaBean。
3. ObjectWrapper:统一属性操作接口
ObjectWrapper
定义了操作对象的统一接口,MyBatis 提供了多种实现:
BeanWrapper 示例
java
public class BeanWrapper extends BaseWrapper {
private final Object object;
private final Reflector reflector;
@Override
public Object get(PropertyTokenizer prop) {
if (prop.getIndex() != null) {
// 处理集合或数组(如 user.addresses[0])
Object collection = getPropertyValue(prop.getName());
return getCollectionValue(prop, collection);
} else {
// 通过 Reflector 获取属性值
return getBeanProperty(prop.getName(), object);
}
}
private Object getBeanProperty(String name, Object object) {
try {
// 从 Reflector 缓存中获取 Getter 方法
Invoker method = reflector.getGetInvoker(name);
return method.invoke(object, NO_ARGS);
} catch (Exception e) {
throw new ReflectionException("Error getting property '" + name + "'", e);
}
}
}
4. ReflectorFactory:反射工厂
ReflectorFactory
采用工厂模式生产 Reflector
,默认实现是 DefaultReflectorFactory
,支持缓存优化:
java
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// 从缓存中获取 Reflector
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
性能优化策略
元信息缓存:
Reflector
和ObjectWrapper
缓存类的属性、方法信息,避免重复解析。方法对象复用: 通过
Invoker
包装Method
或Field
,直接调用method.invoke()
而非反射查找。避免硬编码: 使用
MetaObject
代替直接反射操作,统一处理Map
、Collection
和 JavaBean。
使用示例
动态设置嵌套属性:
java
User user = new User();
MetaObject metaUser = MetaObject.forObject(user, new DefaultReflectorFactory());
metaUser.setValue("address.city", "Beijing"); // 等价于 user.getAddress().setCity("Beijing")
MyBatis 的反射工具类通过以下机制实现高效属性操作:
元信息预解析:
Reflector
预加载类的属性与方法。链式属性访问:
MetaObject
支持复杂表达式的递归解析。统一接口抽象:
ObjectWrapper
屏蔽底层对象类型差异。工厂与缓存:
ReflectorFactory
提升反射性能。