手写MyBatis ORM框架(七)

手写MyBatis ORM框架(七)

引言

在这篇文章之中,我们会详细介绍一下MyBatis中反射工具类的详细设计。

开始

在 MyBatis 中,反射工具类主要用于高效操作 Java 对象的属性、方法和类型信息,其核心目标是支持动态 SQL 参数绑定和结果集映射。以下是 MyBatis 反射工具类的核心实现及其原理的详细说明:


反射工具类的组成

MyBatis 的反射模块主要包含以下核心类:

​类名

​作用

Reflector

缓存类的元信息(属性、方法、类型),提供快速反射操作。

MetaObject

对原始对象的反射操作入口,支持嵌套属性访问。

ObjectWrapper

包装对象,提供统一接口操作属性(如 get/set)。

ReflectorFactory

生产 Reflector 的工厂,默认使用 DefaultReflectorFactory。

PropertyTokenizer

解析复杂属性表达式(如 user.address.city)。


核心实现原理

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)访问。

  • 大小写不敏感:属性名匹配时忽略大小写(如 userNameusername 视为同一属性)。


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 统一处理 MapCollection 和普通 JavaBean。


3. ObjectWrapper:统一属性操作接口

ObjectWrapper 定义了操作对象的统一接口,MyBatis 提供了多种实现:

​实现类

​适用场景

BeanWrapper

包装普通 JavaBean,通过反射操作属性。

MapWrapper

包装 Map 对象,直接通过 key 访问属性。

CollectionWrapper

包装 Collection,支持索引访问(如 list[0])。

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);
        }
    }
}

性能优化策略

  1. 元信息缓存ReflectorObjectWrapper 缓存类的属性、方法信息,避免重复解析。

  2. 方法对象复用: 通过 Invoker 包装 MethodField,直接调用 method.invoke() 而非反射查找。

  3. 避免硬编码: 使用 MetaObject 代替直接反射操作,统一处理 MapCollection 和 JavaBean。


使用示例

动态设置嵌套属性:

java

User user = new User();
MetaObject metaUser = MetaObject.forObject(user, new DefaultReflectorFactory());
metaUser.setValue("address.city", "Beijing"); // 等价于 user.getAddress().setCity("Beijing")

MyBatis 的反射工具类通过以下机制实现高效属性操作:

  1. 元信息预解析Reflector 预加载类的属性与方法。

  2. 链式属性访问MetaObject 支持复杂表达式的递归解析。

  3. 统一接口抽象ObjectWrapper 屏蔽底层对象类型差异。

  4. 工厂与缓存ReflectorFactory 提升反射性能。

流程图

LICENSED UNDER CC BY-NC-SA 4.0