mybatis原理分析(六)---MetaObject

文章目录

      • 1.概述
      • 2.MetaObject实现依赖
      • 3.MetaObject获取属性的流程
        • 3.1 流程图
        • 3.2 源码分析
      • 4.MetaObject设置属性的流程

1.概述

在上一篇博客《mybatis原理分析(五)—参数处理》中介绍了参数处理的过程,分析了相关的源码。其中用到了MetaObject这个工具类来处理属性值,但并没有详细的介绍这个工具类有什么特点,又是如何工作的,所以这篇博客主要介绍MetaObject的特点和原理。

结果集映射的时候也会使用到这个工具类,所谓映射是指结果集中的列填充至JAVA Bean属性。这就必须用到反射,而Bean的属性是多种多样的有普通属性、对象、集合、Map等等。为了更加方便的操作Bean的属性,MyBatis提供了MetaObject 工具类,其简化了对象属性的操作。其具体的功能如下:

  1. 获取属性

    • 基于点获取子属性 “user.name”
    • 基于索引获取列表值 “users[1].id”
    • 基于key获取map值 “user[name]”
  2. 设置属性:

    • 可设置子属性值
    • 支持自动创建子属性(必须带有空参构造方法,且不能是集合)

2.MetaObject实现依赖

为了实现上述的功能,MetaObject依赖了BeanWrapper、MetaClass、Reflector。

  • BeanWrapper: 功能与MeataObject类似,不同点是BeanWrapper只针对单个当前对象属性进行操作,不能操作子属性。例如可以获取当前对象的user属性,但是不能获取当前对象的user属性下的name子属性

  • MetaClass :类的反射功能支持,获取整完整类的属性,包括属性的属性。

  • Reflector :类的反射功能支持,仅支持当前类的属性。

3.MetaObject获取属性的流程

分析这个流程可以通过编写一个测试代码,跟着debug来看

测试代码如下:

mybatis原理分析(六)---MetaObject_第1张图片

mybatis原理分析(六)---MetaObject_第2张图片

创建了一个Blog对象,里面包括了user和Comment集合,Comment集合中包括了user。

将这个Blog对象封装成MetaObject,然后调用getValue就可以获取到属性值。

3.1 流程图

mybatis原理分析(六)---MetaObject_第3张图片

3.2 源码分析

首先进入的是getValue方法,第一步会对传入的参数name 进行分词

mybatis原理分析(六)---MetaObject_第4张图片

下面是具体分词的源码

mybatis原理分析(六)---MetaObject_第5张图片

  1. 在fullname中从前往后找,找到第一个“.",

    • 如果找到了,则根据这个点将fullname拆开成两部分。name是"."之前的部分,children是“.“之后的部分。
    • 如果没有找到,则name就等于fullname,children为空
  2. 接着将indexedName设置为name

  3. 然后从name中找"["

    • 如果找到了,说明这是一个集合
    • 索引就等于"[]"内的值,
    • name修改成“[]”前的值

测试代码的结果如下:

mybatis原理分析(六)---MetaObject_第6张图片

第一步分词就结束了,回到getValue方法中。接着会调用hasNext判断分词结果中的children是否为空,如果不为空的话,说明有子属性。本例子中子属性不为空 成立,进入第一个if。

mybatis原理分析(六)---MetaObject_第7张图片

metaObjectForProperty是根据分词结果中的indexedName 来获得对象并封装成metaObject。

在这里插入图片描述
首先调用getValue,获取属性值

mybatis原理分析(六)---MetaObject_第8张图片

跟上面一样先分词,此时并没有子属性,所以会调用objectWrapper.get

mybatis原理分析(六)---MetaObject_第9张图片

根据分词的index来判断是否是集合,如果是集合的话调用getCollectionValue来获取属性值

如果不是的话调用getBeanProperty来获取属性值。都是通过反射来获取的。

然后代码回到了metaObjectForProperty方法

在这里插入图片描述

调用MetaObject.forObject 将得到的Comment[0]对象封装成MetaObject

返回到getValue方法中,

此时得到了Comments[0]对象封装后的MetaObject对象,也就是这里的metaValue。

之后会调用metaValue.getValue来解析它的属性。也就是user.name

mybatis原理分析(六)---MetaObject_第10张图片

之后的逻辑就是上面的重复的递归了,对name进行分词,分词后,根据反射得到属性对应的属性值,再将这个属性值封装成MetaObject对象。然后调用getValue继续解析子属性。直到最后没有子属性了,就这样获取到了目标属性值。

4.MetaObject设置属性的流程

设置属性的流程和上面获取属性的流程差不多,不同在于如果子属性不存在,则会尝试创建子属性。

测试代码如下:

mybatis原理分析(六)---MetaObject_第11张图片
mybatis原理分析(六)---MetaObject_第12张图片

首先也是分词,判断有没有子属性。

如果有子属性,则先根据反射得到当前分词中indexedName的属性值,然后将它封装成MetaObject对象,如果属性值不存在,则会尝试创建,然后再用新的MetaObject递归调用setValue方法。

最终找到要设置的子属性的位置,基于反射设置属性。

你可能感兴趣的:(#,mybatis,原理分析,java,mybatis,MetaObject)