在使用MyBatis进行开发时,你是否好奇过:
- MyBatis如何将ResultSet数据自动映射到Java对象?
- 它是如何在运行时动态操作对象属性的?
- 为什么MyBatis能够处理各种复杂的嵌套属性?
这一切的背后,都离不开其强大而精巧的反射模块。作为MyBatis框架的“核心基础设施”,反射模块承担了对象操作的重任,是理解MyBatis工作原理的关键。
一、MyBatis整体架构与反射模块
1.1 反射模块在MyBatis中的位置

从上图所示的MyBatis整体架构中可以看到,整个框架采用了清晰的分层设计。反射模块(Reflection)位于基础支撑层,与类型处理、日志、缓存等模块并列,为上层的数据映射、SQL执行等核心功能提供底层的对象操作支持。
1.2 反射模块的五大核心职责
- 对象属性访问 - 通过反射高效读写对象属性。
- 对象实例化 - 动态创建各种类型的对象实例。
- 类型解析 - 分析并缓存类的类型信息,包括泛型。
- 元数据获取 - 获取方法、字段、构造器等元数据。
- 性能优化 - 通过缓存反射信息,避免重复解析,大幅提升性能。
1.3 为什么需要反射模块?
试想一下,如果没有它,MyBatis将如何工作?
- 场景1:结果映射
ResultSet → 提取数据 → 通过反射设置到Java对象
- 场景2:参数传递
Java对象 → 通过反射获取属性值 → 设置到PreparedStatement
- 场景3:对象创建
Mapper返回类型 → 通过反射创建实例 → 填充数据
- 场景4:元数据解析
XML配置 → 解析类名 → 通过反射获取类信息
没有反射模块,上述每一个操作都需要开发者手工编写大量重复且易错的样板代码。反射模块的价值就在于封装复杂度,提供统一、高效的API。
1.4 Java反射基础回顾
在深入MyBatis的实现之前,先快速回顾一下标准Java反射API的基本用法:
// 获取Class对象
Class<?> clazz = User.class;
// 创建实例(需要无参构造)
Object obj = clazz.newInstance();
// 获取方法
Method method = clazz.getMethod("setName", String.class);
// 调用方法
method.invoke(obj, "张三");
// 获取字段(即使是私有的)
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(obj, "张三");
原生反射API虽然强大,但直接使用存在性能开销大、代码冗长、异常处理繁琐等问题。MyBatis的反射模块正是在此基础上进行了深度优化和封装。
二、反射模块架构

2.1 反射模块组成
反射模块是一个精心设计的组件集合,职责分明:
- Reflection(反射模块)
- ├── ObjectFactory(对象工厂) - 负责对象创建
- ├── PropertyTokenizer(属性分词器) - 解析复杂属性表达式
- ├── PropertyCopier(属性复制器) - 对象间属性复制
- ├── Reflector(反射器) - 核心,缓存类反射信息
- ├── MetaClass(元数据类) - 封装Reflector,提供友好API
- ├── MetaObject(元对象) - 统一入口,支持多种对象类型
- └── SystemMetaObject(系统元对象) - 工具类
2.2 ObjectFactory - 对象工厂
ObjectFactory 定义了创建对象实例的接口,其设计简洁而强大:
public interface ObjectFactory {
// 创建对象实例(无参)
<T> T create(Class<T> type);
// 创建对象实例(带构造参数)
<T> T create(Class<T> type,
Class<?>[] classes,
Object[] values);
// 判断是否为集合类型
<T> boolean isCollection(Class<T> type);
}
默认实现 DefaultObjectFactory 的核心逻辑清晰:
public class DefaultObjectFactory implements ObjectFactory {
@Override
public <T> T create(Class<T> type) {
try {
// 尝试调用无参构造器
return type.newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Error creating instance of " + type, e);
}
}
@Override
public <T> T create(Class<T> type,
Class<?>[] classes,
Object[] values) {
try {
// 查找匹配参数类型的构造器
Constructor<?> constructor =
type.getDeclaredConstructor(classes);
constructor.setAccessible(true);
return (T) constructor.newInstance(values);
} catch (Exception e) {
// 如果带参构造失败,则回退到无参构造
}
return create(type);
}
}
2.3 PropertyTokenizer - 属性分词器
这个精巧的类用于解析像 user.address.city 或 orders[0].itemName 这样的复杂属性表达式。
public class PropertyTokenizer
implements Iterator<PropertyTokenizer> {
private String fullname; // 完整属性表达式,如 “user.address.city”
private String name; // 当前层名称,如第一次迭代是 “user”
private String indexedName; // 索引名称,如 “list”
private String index; // 索引值,如 “0”
private String children; // 剩余子属性,如第一次迭代后是 “address.city”
public PropertyTokenizer(String fullname) {
this.fullname = 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;
// 解析索引 例如:list[0]
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); // 递归解析下一层
}
}
使用示例:
String expression = "user.address.city";
PropertyTokenizer tokenizer =
new PropertyTokenizer(expression);
while (tokenizer.hasNext()) {
System.out.println(
"Current: " + tokenizer.getName());
tokenizer = tokenizer.next();
}
// 输出:
// Current: user
// Current: address
// Current: city
2.4 PropertyCopier - 属性复制器
PropertyCopier 用于在两个对象之间复制属性值,其实现依赖于元数据类:
public class PropertyCopier {
public void copyProperties(Object source,
Object target) {
// 获取源和目标对象的元数据
MetaClass sourceMetaClass =
MetaClass.forClass(source.getClass());
MetaClass targetMetaClass =
MetaClass.forClass(target.getClass());
// 获取源对象的所有可读属性名
String[] getterNames =
sourceMetaClass.getGetterNames();
for (String name : getterNames) {
// 检查目标对象是否有对应的setter方法
if (targetMetaClass.hasSetter(name)) {
try {
// 获取源对象属性值
Object value = sourceMetaClass
.getGetter(name)
.invoke(source);
// 设置到目标对象
targetMetaClass
.getSetter(name)
.invoke(target, value);
} catch (Exception e) {
// 忽略无法复制的属性(如类型不匹配)
}
}
}
}
}
三、对象属性访问

3.1 Reflector - 反射器
Reflector 是整个反射模块的心脏,它会在类首次被访问时,解析并缓存其所有的反射信息,避免后续重复解析带来的性能损耗。
public class Reflector {
// 类类型
private final Class<?> type;
// 可读属性映射:属性名 -> getter方法调用器
private final Map<String, Invoker> getMethods
= new HashMap<>();
// 可写属性映射:属性名 -> setter方法调用器
private final Map<String, Invoker> setMethods
= new HashMap<>();
// 属性类型映射
private final Map<String, Class<?>> getTypes
= new HashMap<>();
private final Map<String, Class<?>> setTypes
= new HashMap<>();
// 所有已识别属性名的集合
private final Set<String> properties
= new HashSet<>();
public Reflector(Class<?> clazz) {
this.type = clazz;
addDefaultConstructor(clazz); // 查找默认构造器
addGetMethods(clazz); // 扫描并缓存所有getter
addSetMethods(clazz); // 扫描并缓存所有setter
addFields(clazz); // 补充通过字段直接访问的属性
}
}
添加getter方法的核心逻辑展示了其如何遵循JavaBean规范:
private void addGetMethods(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// 处理 getXxx() 方法
if (method.getName().startsWith("get")
&& method.getParameterTypes().length == 0) {
String name = method.getName().substring(3);
name = Character.toLowerCase(name.charAt(0))
+ name.substring(1);
addGetMethod(name, method);
}
// 处理 isXxx() 布尔方法
else if (method.getName().startsWith("is")
&& method.getParameterTypes().length == 0
&& method.getReturnType() == boolean.class) {
String name = method.getName().substring(2);
name = Character.toLowerCase(name.charAt(0))
+ name.substring(1);
addGetMethod(name, method);
}
}
}
MetaClass 在 Reflector 之上提供了一个更友好、更安全的API层,隐藏了底层缓存的细节。
public class MetaClass {
private final Reflector reflector;
// 获取属性值
public Object getValue(String name, Object obj) {
try {
Invoker method =
reflector.getGetInvoker(name);
return method.invoke(obj);
} catch (Exception e) {
throw new RuntimeException(
"Error getting property '" + name + "'", e);
}
}
// 设置属性值
public void setValue(String name,
Object obj,
Object value) {
try {
Invoker method =
reflector.getSetInvoker(name);
method.invoke(obj, value);
} catch (Exception e) {
throw new RuntimeException(
"Error setting property '" + name + "'", e);
}
}
// 获取属性的getter返回类型
public Class<?> getGetterType(String name) {
return reflector.getGetterType(name);
}
// 检查属性是否有getter/setter
public boolean hasGetter(String name) {
return reflector.hasGetter(name);
}
public boolean hasSetter(String name) {
return reflector.hasSetter(name);
}
}
MetaObject 是反射模块对外的统一门面(Facade)。它最大的特点是能够透明地处理不同类型的对象(JavaBean、Map、Collection),并支持嵌套属性访问。
public abstract class MetaObject {
private Object originalObject;
private MetaClass metaClass;
private ObjectWrapper objectWrapper;
// 获取属性值(支持嵌套)
public Object getValue(String name) {
PropertyTokenizer prop =
new PropertyTokenizer(name);
if (prop.hasNext()) {
// 处理嵌套属性,递归获取
return metaClass.getValue(
prop.getName(), originalObject);
} else {
// 当前层属性,委托给ObjectWrapper
return objectWrapper.get(prop);
}
}
// 设置属性值(支持嵌套)
public void setValue(String name, Object value) {
PropertyTokenizer prop =
new PropertyTokenizer(name);
if (prop.hasNext()) {
metaClass.setValue(
prop.getName(), originalObject, value);
} else {
objectWrapper.set(prop, value);
}
}
// 工厂方法:根据对象类型创建对应的MetaObject
public static MetaObject forObject(
Object object,
ObjectFactory objectFactory,
ObjectWrapperFactory objectWrapperFactory) {
if (object == null) {
return SystemMetaObject.NULL_META_OBJECT;
}
// 根据对象类型分发创建逻辑
if (object instanceof Map) {
return new MapMetaObject(
(Map) object,
objectFactory,
objectWrapperFactory);
} else if (object instanceof Collection) {
return new CollectionMetaObject(
(Collection) object,
objectFactory,
objectWrapperFactory);
} else {
// 普通JavaBean
return new BeanMetaObject(
object,
objectFactory,
objectWrapperFactory);
}
}
}
四、对象实例化

4.1 ObjectFactory创建对象
在实际使用中,ObjectFactory 让对象创建变得非常简单:
ObjectFactory objectFactory =
new DefaultObjectFactory();
// 创建简单对象(调用无参构造)
User user = objectFactory.create(User.class);
// 创建带参对象
Class<?>[] classes = {String.class, String.class};
Object[] values = {"张三", "zhangsan@example.com"};
User user = objectFactory.create(
User.class, classes, values);
// 创建集合对象(ObjectFactory知道如何实例化接口)
List<User> users =
objectFactory.create(ArrayList.class);
4.2 处理特殊类型
我们可以通过扩展 DefaultObjectFactory 来处理接口或抽象类等特殊类型的实例化需求:
public class CustomObjectFactory
extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type) {
// 处理接口类型
if (type.isInterface()) {
if (type.equals(List.class)) {
return (T) new ArrayList<>();
} else if (type.equals(Map.class)) {
return (T) new HashMap<>();
}
throw new RuntimeException(
"Cannot create instance of interface: "
+ type);
}
// 处理抽象类
if (Modifier.isAbstract(type.getModifiers())) {
throw new RuntimeException(
"Cannot create instance of abstract class: "
+ type);
}
return super.create(type);
}
}
4.3 对象包装器 - ObjectWrapper
ObjectWrapper 接口定义了统一的属性访问契约,使得 MetaObject 能够以相同的方式操作Bean、Map和Collection。
public interface ObjectWrapper {
// 获取属性值
Object get(PropertyTokenizer prop);
// 设置属性值
void set(PropertyTokenizer prop, Object value);
// 获取属性类型
Class<?> getSetterType(String name);
// 判断是否存在setter/getter
boolean hasSetter(String name);
boolean hasGetter(String name);
}
BeanWrapper 是处理普通JavaBean的实现,其 get 方法展示了如何处理嵌套属性:
public class BeanWrapper extends BaseWrapper
implements ObjectWrapper {
private final Object object;
private final MetaClass metaClass;
@Override
public Object get(PropertyTokenizer prop) {
try {
Invoker method = metaClass.getGetInvoker(
prop.getName());
Object value = method.invoke(object);
if (prop.hasNext() && value != null) {
// 递归获取嵌套属性:为子对象创建新的MetaObject
return MetaObject
.forObject(value, ...)
.getValue(prop.getChildren());
}
return value;
} catch (Throwable t) {
throw new RuntimeException(
"Error getting property '"
+ prop.getName() + "'", t);
}
}
// ... set方法逻辑类似,支持嵌套设置
}
五、类型解析

5.1 TypeParameterResolver - 泛型解析
这个工具类用于解析复杂的泛型类型信息,确保在映射时能获取到准确的类型。
public class TypeParameterResolverImpl
implements TypeParameterResolver {
private final Type type;
@Override
public Type resolveType(Type rawType, Type jniType) {
// 解析泛型类型
if (rawType instanceof Class) {
return resolveClass((Class<?>) rawType);
} else if (rawType instanceof ParameterizedType) {
return resolveParameterizedType(
(ParameterizedType) rawType);
} else if (rawType instanceof GenericArrayType) {
return resolveGenericArrayType(
(GenericArrayType) rawType);
}
return rawType;
}
}
5.2 TypeAliasRegistry - 类型别名
TypeAliasRegistry 维护了一个别名到实际类名的映射,极大地简化了XML配置。
public class TypeAliasRegistry {
// 别名(小写)到类型的映射
private final Map<String, Class<?>> typeAliases
= new HashMap<>();
// 注册类型别名
public void registerAlias(String alias,
Class<?> value) {
if (alias == null) {
throw new TypeException(
"Type alias cannot be null");
}
typeAliases.put(alias, value);
}
// 根据别名解析类型
public Class<?> resolveAlias(String string) {
if (string == null) {
return null;
}
String key = string.toLowerCase(Locale.ENGLISH);
Class<?> value = typeAliases.get(key);
if (value == null) {
try {
// 如果别名未注册,尝试直接加载类
return Class.forName(string);
} catch (ClassNotFoundException e) {
throw new TypeException(
"Could not resolve type alias '"
+ string + "'", e);
}
}
return value;
}
}
5.3 TypeHandlerRegistry - 类型处理器
TypeHandlerRegistry 是JDBC类型与Java类型转换的中央枢纽。
public class TypeHandlerRegistry {
// 多层映射:Java类型 -> JDBC类型 -> 具体的TypeHandler
private final Map<Type, Map<JdbcType, TypeHandler<?>>>
typeHandlerMap = new HashMap<>();
// 获取类型处理器
public <T> TypeHandler<T> getTypeHandler(
Type type,
JdbcType jdbcType) {
Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap
= typeHandlerMap.get(type);
if (jdbcTypeHandlerMap != null) {
TypeHandler<?> handler =
jdbcTypeHandlerMap.get(jdbcType);
if (handler != null) {
return (TypeHandler<T>) handler;
}
}
// 找不到对应类型的处理器,返回默认的Object处理器
return getTypeHandler(Object.class);
}
}
六、元数据获取

6.1 获取类信息
反射模块需要获取类的基本信息以进行后续操作。
public class ClassInfo {
public static void analyze(Class<?> clazz) {
System.out.println("类名: " + clazz.getName());
System.out.println("简单名称: " + clazz.getSimpleName());
System.out.println("包名: " + clazz.getPackage().getName());
System.out.println("父类: " + clazz.getSuperclass().getName());
System.out.println("接口: " + Arrays.toString(clazz.getInterfaces()));
// 获取修饰符
int modifiers = clazz.getModifiers();
System.out.println("是否为public: " + Modifier.isPublic(modifiers));
System.out.println("是否为abstract: " + Modifier.isAbstract(modifiers));
}
}
6.2 获取方法信息
准确识别getter和setter方法是实现属性映射的基础。
public class MethodInfo {
// 判断是否为getter方法
private static boolean isGetter(Method method) {
String name = method.getName();
return (name.startsWith("get")
&& name.length() > 3
&& method.getParameterTypes().length == 0)
|| (name.startsWith("is")
&& name.length() > 2
&& method.getParameterTypes().length == 0
&& method.getReturnType() == boolean.class);
}
// 判断是否为setter方法
private static boolean isSetter(Method method) {
String name = method.getName();
return name.startsWith("set")
&& name.length() > 3
&& method.getParameterTypes().length == 1
&& method.getReturnType() == void.class;
}
// 从方法名提取属性名
private static String getPropertyName(Method method) {
String name = method.getName();
if (name.startsWith("get") || name.startsWith("set")) {
name = name.substring(3);
} else if (name.startsWith("is")) {
name = name.substring(2);
}
// 将首字母转为小写(遵循JavaBean规范)
return Character.toLowerCase(name.charAt(0))
+ name.substring(1);
}
}
6.3 ReflectorFactory - 工厂模式
ReflectorFactory 采用工厂模式管理 Reflector 实例,并实现全局缓存,这是性能优化的核心。
public class ReflectorFactory {
// 使用并发Map缓存Reflector,键为Class对象
private final ConcurrentMap<Class<?>, Reflector>
reflectorMap = new ConcurrentHashMap<>();
// 获取Reflector(如果缓存中没有则创建并缓存)
public Reflector findForClass(Class<?> type) {
return reflectorMap.computeIfAbsent(type, k -> {
return new Reflector(k); // 创建过程可能较耗时,但仅一次
});
}
public boolean hasReflectorFor(Class<?> type) {
return reflectorMap.containsKey(type);
}
}
七、最佳实践
7.1 性能优化建议
- ✅ 利用内置缓存:
Reflector 和 ReflectorFactory 已实现缓存,无需自己额外缓存Class信息。
- ✅ 优先使用高层API:尽量使用
MetaObject 而非直接操作 Reflector 或原生反射API,其内部已做优化。
- ✅ 注意对象创建开销:在极高并发场景,可考虑池化频繁创建的对象或使用自定义
ObjectFactory进行优化。
- ✅ 延迟加载:MyBatis本身是懒加载的,确保你的实体类设计与之匹配,避免不必要的元数据解析。
7.2 使用建议
- ✅ 首选MetaObject:进行动态属性操作时,
MetaObject.forObject() 是你的首选工具。
- ✅ 继承BaseWrapper:如需实现自定义的对象包装逻辑,继承
BaseWrapper 可以省去大量工作。
- ✅ 扩展ObjectFactory:当你有特殊的对象实例化需求(如依赖注入、使用特定构造器),自定义
ObjectFactory是标准方式。
- ✅ 善用类型别名:在MyBatis配置文件中注册类型别名,可以使配置文件更简洁清晰。
7.3 常见问题解决
问题1:属性映射失败,提示找不到getter/setter。
// 错误原因:属性名不匹配
// User类字段:userName
// getter方法:getName() ❌ 不符合JavaBean规范
// 正确做法:确保方法名与字段名对应
public String getUserName() { // ✅
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
问题2:如何访问嵌套属性或集合元素?
MetaObject 完美支持复杂的属性表达式。
MetaObject metaObject = MetaObject.forObject(user, ...);
// 直接访问
Object address = metaObject.getValue("address");
// 嵌套访问
Object city = metaObject.getValue("address.city");
// 带索引的访问(假设orders是一个List)
Object item = metaObject.getValue("orders[0].itemName");
问题3:自定义类型如何与数据库类型转换?
通过注册自定义的 TypeHandler 来解决。
// 使用TypeHandlerRegistry处理类型转换
TypeHandlerRegistry registry = new TypeHandlerRegistry();
TypeHandler<String> handler =
registry.getTypeHandler(String.class);
// 设置参数到PreparedStatement
handler.setParameter(ps, 1, "张三");
// 从ResultSet获取结果
String result = handler.getResult(rs, "name");
八、总结
关键组件回顾
- ObjectFactory - 对象工厂,负责所有对象实例的创建。
- PropertyTokenizer - 属性分词器,解析
user.address.city 这类表达式。
- PropertyCopier - 属性复制器,实现对象间属性拷贝。
- Reflector - 反射器,缓存类的反射信息,性能基石。
- MetaClass - 元数据类,封装Reflector,提供更友好的操作接口。
- MetaObject - 元对象,统一门面,支持Bean、Map、Collection等多种类型的透明操作。
设计思想精髓
MyBatis反射模块的设计处处体现着经典软件工程思想:
- 💎 缓存优化:通过
ReflectorFactory 等组件缓存元数据,空间换时间,避免重复反射。
- 💎 封装复杂度:将繁琐的原生反射API封装在底层,对外提供如
MetaObject.getValue() 这样简洁的API。
- 💎 统一接口:
ObjectWrapper 和 MetaObject 定义了统一的操作契约,隔离了不同数据类型的差异。
- 💎 扩展性强:通过工厂模式(
ObjectFactory, ReflectorFactory)和注册机制(TypeAliasRegistry),允许用户轻松扩展。
- 💎 性能优先:整个设计贯穿了“一次解析,多次使用”的原则,确保了框架在高并发下的性能。
结语
MyBatis的反射模块远不止是 Java.lang.reflect 的简单包装。它是一个经过深度优化、结构清晰、扩展性强的对象操作基础设施。理解其内部机制,不仅能帮助我们更高效地使用MyBatis,避免常见的坑,更能学习到如何在框架设计中平衡灵活性、性能与易用性。希望这篇深入剖析能成为你探索MyBatis乃至其他优秀框架设计之美的起点。
本文由云栈社区技术团队整理,旨在深度解析主流框架的核心原理。欢迎在社区交流更多关于JVM与设计模式的实战经验。