mybatis MetaObject 浅析

本文详细介绍了MyBatis框架中的MetaObject类的基本使用方法,包括如何通过MetaObject操作JavaBean、Collection和Map类型的对象,同时展示了如何利用属性分词器实现复杂属性的设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

本文介绍关于 MetaObject 的说明和使用

基本使用方法

public class Animal {
    private Animal parent;
    private String name;
    // 省略 getter, setter
}

javaBean

    @Test
    public void testBean(){
        Animal animal = new Animal();
        MetaObject metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.setValue("name","bean");
        System.out.println(animal.getName());
    }

控制台输出:bean

Collection

  @Test
    public void testCollection(){
        Animal animal = new Animal();
        animal.setName("collection");
        List<Animal> list = new ArrayList<>();
        MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.add(animal);
        System.out.println(list.get(0).getName());
    }

控制台输出:collection

Map

    @Test
    public void testMap(){
        Animal animal = new Animal();
        animal.setName("map");
        Map<String,Animal> map = new HashMap<>();
        MetaObject metaObject = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.setValue("deer",animal);
        System.out.println(map.get("deer").getName());
    }

控制台输出:map

分隔符赋值

    @Test
    public void testTokenizer(){
        Animal animal = new Animal();
        animal.setParent(new Animal());
        MetaObject metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.setValue("parent.name","tokenizer");
        System.out.println(animal.getParent().getName());
    }

控制台输出:tokenizer

分析

创建对象

MetaObject 内部具有5个字段,对外提供的所有方法都是基于这5个字段的。

将这5个字段的方法取一部分对外部提供服务的组合模式

  // 原始对象
  private final Object originalObject;
  private final ObjectWrapper objectWrapper;
  private final ObjectFactory objectFactory;
  private final ObjectWrapperFactory objectWrapperFactory;
  private final ReflectorFactory reflectorFactory;

MetaObject 的构造器是私有的,只提供 forObject 创建MetaObject对象.

当参数object为null时,返回 SystemMetaObject.NullObject.class 对象的元数据

 public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
    // 记录了Class 相关的getter
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

创建对象-对象包装器

ObjectWrapper 是一个对象包装器,提供了对Bean,Collection,Map 不同的操作方式

  1. BeanWrapper
    提供了 object.setName,object.setAge 以及类似 object.getParent().setName(),object.getParent().getParent().setName() 的赋值方式
  2. MapWrapper
    提供了 object.getName,object.getAge 以及类似 object.getParent().getName(),object.getParent().getParent().getName() 的取值方式
  3. CollectionWrapper
    提供了 集合的add,addAll 方法, setValue,getValue hasSetter 等方法均抛出异常

实战

CollectionWrapper 分析

在例子中,想取出集合的第一个元素怎么办?

  @Test
    public void testCollectionGet(){
        Animal animal = new Animal();
        animal.setName("collection");
        List<Animal> list = new ArrayList<>();
        MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.add(animal);
        Animal convert = (Animal) metaObject.getValue("[0]");
        System.out.println(convert.getName());
    }

控制台输出

java.lang.UnsupportedOperationException
    at org.apache.ibatis.reflection.wrapper.CollectionWrapper.get(CollectionWrapper.java:38)
    at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
    at com.aya.MetaObjectTest.testCollection(MetaObjectTest.java:31)
    ...

并没有输出我们想要的 collection

分析CollectionWrapper的get方法

org.apache.ibatis.reflection.wrapper.CollectionWrapper

  @Override
  public Object get(PropertyTokenizer prop) {
    throw new UnsupportedOperationException();
  }

BeanWrapper 分析

    @Test
    public void testCustomBeanWrapper(){
        Animal animal = new Animal();
        animal.setName("customBeanWrapper");
        List<Animal> list = new ArrayList<>();
        MetaObject metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
        metaObject.add(animal);

        BeanWrapper beanWrapper = new BeanWrapper(metaObject, list);
        Animal convertAnimal = (Animal)beanWrapper.get(new PropertyTokenizer("[0]"));
        System.out.println(convertAnimal.getName());
    }

控制台输出: customBeanWrapper

CollectionWrapper 无法进行get操作,因为它重写了get并抛出了异常, MapWrapper和BeanWrapper 并没有重写get.

所以可以包装一层, 用 BeanWrapper 来访问集合的属性

总结

元数据对象(MetaObject)实际上就是提供 类|集合|Map 的一种自动识别的访问形式.

属性分词器

PropertyTokenizer 是mybatis的属性分词器

提供了对象和集合的一种概念形式, 只是记录了属性有没有子属性

例如: object.parent.name

只是记录了 object 而已,可以通过next方法创建一个对象,返回new PropertyTokenizer(“parent”)
再次调用next 返回new PropertyTokenizer(“name”)

<think>好的,我需要分析用户的问题,用户想了解MyBatisMetaObject的工作原理和实现机制。首先,我需要回忆MyBatis的相关知识,特别是MetaObject的作用。MetaObject主要用于简化对JavaBean属性的访问,支持嵌套属性和集合操作。接下来,结合用户提供的引用内容,尤其是引用[2],其中提到了MetaObject、BeanWrapper、MetaClass、ReflectorFactory和Reflector,这些都是MetaObject实现的关键组件。 我需要分步骤解释MetaObject的工作原理。首先,MetaObject通过包装目标对象,提供统一的访问接口。然后,内部可能使用BeanWrapper来处理JavaBean的属性,而MetaClass和Reflector用于反射操作,缓存类的元数据信息,提高访问效率。ReflectorFactory可能负责创建和管理Reflector实例,避免重复反射带来的性能问题。 还要注意用户提供的引用中提到的配置解析和拦截器机制,虽然这些可能与MetaObject没有直接关联,但需要确保不混淆。需要详细说明MetaObject如何利用反射机制获取和设置属性,如何处理嵌套属性如user.address.street,以及如何通过缓存元数据来优化性能。此外,应结合用户给出的代码结构,可能提到MetaObject的使用示例,但用户没有提供具体代码,所以需要保持描述清晰。 最后,生成相关问题时要确保问题与MetaObject相关,比如设计目的、反射优化、处理嵌套属性的方法,以及与反射直接操作的区别。需要确保回答结构清晰,符合用户要求的步骤分解,同时正确引用标记,比如引用[^2]对应到用户给的引用[2]。</think>### MyBatis MetaObject 工作原理及实现机制分步解析 #### 1. MetaObject 的核心作用 MetaObjectMyBatis 提供的**对象属性操作工具类**,主要实现以下功能: - **统一访问接口**:对普通对象、Map、集合等不同数据结构的属性访问提供统一语法 - **嵌套属性解析**:支持多级属性访问(如 `user.address.street`) - **类型自动适配**:自动处理泛型集合、数组等复杂类型 - **反射优化**:通过缓存反射信息提升属性操作性能 #### 2. 核心组件协作关系 通过引用[2]提到的组件,其协作关系如下: ``` MetaObject → BeanWrapper → MetaClass → Reflector → ReflectorFactory ``` - **MetaObject**:对外暴露操作接口的入口类 - **BeanWrapper**:具体处理对象属性操作的实现类 - **MetaClass**:维护类元数据(属性/方法信息) - **Reflector**:实际执行反射操作的底层类 - **ReflectorFactory**:Reflector 的工厂类,负责缓存和复用 #### 3. 实现机制详解 **步骤 1:对象包装** ```java MetaObject meta = MetaObject.forObject(target, objectFactory); ``` - 根据目标对象类型自动选择包装策略 - 支持普通 POJO、Map、Collection 等类型 **步骤 2:属性解析(以 `user.roles[0].name` 为例)** 1. 拆分属性表达式为 `user` → `roles` → `[0]` → `name` 2. 递归处理每个属性节点: ```java Object value = meta.getValue("user.roles[0].name"); ``` **步骤 3:反射优化实现** - 通过 Reflector 缓存类信息(引用[2]): ```java public class Reflector { private Map<String, Invoker> getMethods = new HashMap<>(); private Map<String, Invoker> setMethods = new HashMap<>(); private Map<String, Class<?>> getTypes = new HashMap<>(); // 缓存构造时解析的类成员信息 } ``` - ReflectorFactory 确保每个类只创建一个 Reflector 实例 **步骤 4:集合处理** - 自动识别 List/Map/Array 等集合类型 - 通过 `ObjectCollectionWrapper` 处理集合元素访问 #### 4. 性能优化关键点 1. **元数据缓存**:MetaClass 缓存类的属性/方法信息,避免重复反射 2. **类型推断**:提前解析泛型类型信息(如 `List<User>` 的泛型参数) 3. **访问器缓存**:将 Method 对象包装为 Invoker 进行缓存 #### 5. 典型使用场景 - 动态 SQL 处理(`<if test="user.name != null">`) - 结果集映射(ResultMap 实现) - 插件开发时的参数处理(引用[3]) : MyBatisMetaObject 通过反射机制和元数据缓存实现了高效的属性操作,其核心设计在 BeanWrapper 和 Reflector 的协作中体现。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值