Mybatis框架源码笔记(九)之反射工具类解析

1 反射工具类

Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错。Mybatis框架提供了专门的反射包,对常用的反射操作进行了简化封装,提供了更简单方便的API给调用者进行使用,主要的反射包代码结果如下:
在这里插入图片描述

2 核心接口

2.1 ObjectFactory接口

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。
在这里插入图片描述

2.2 ReflectorFactory接口

Mybatis使用一个 ReflectorFactory对象工厂去创建Reflector对象, 每一个Reflector对应一个java的Class类,其中包含了这个java的Class类的元信息,而 ReflectorFactory对象工厂就是用来创建并缓存Reflector对象的。
在这里插入图片描述

2.3 Invoker接口

Mybatis使用一个 Invoker接口来扩展java的Class类中的方法的调用执行,包含getter/setter以及其他方法和未明确方法的调用执行。
在这里插入图片描述

2.4 ObjectWrapper接口

ObjectWrapper 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型,它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。
在这里插入图片描述

3 核心类

3.1 Reflector类

Reflector中存储了反射需要使用的类的元信息(字节码的类型、属性、getter/setter、数据类型、构造器等等)
在这里插入图片描述
在这里插入图片描述
然后我们可以看看Reflector中提供的公共的API方法

方法名称 作用
getType 获取Reflector表示的Class
getDefaultConstructor 获取默认的构造器
hasDefaultConstructor 判断是否有默认的构造器
getSetInvoker 根据属性名称获取对应的Invoker 对象
getGetInvoker 根据属性名称获取对应的Invoker对象
getSetterType 获取属性对应的类型 比如:
String name; // getSetterType(“name”) --> java.lang.String
getGetterType 与上面是对应的
getGetablePropertyNames 获取所有的可读属性名称的集合
getSetablePropertyNames 获取所有的可写属性名称的集合
hasSetter 判断是否具有某个可写的属性
hasGetter 判断是否具有某个可读的属性
findPropertyName 根据名称查找属性

3.2 DefaultReflectorFactory类

Mybatis框架内置的默认的创建Reflector对象的工厂类
在这里插入图片描述

3.3 MetaClass类

MetaClass 则用于获取类相关的信息。
在这里插入图片描述

方法 说明
静态方法 forClass(type, reflectorFactory) 创建 MetaClass 对象
hasDefaultConstructor() 判断是否有默认构造方法
hasGetter(name) 判断是否有属性 name 或 name 的 getter 方法。与 MetaObject 判断类似。
getGetterNames() 获取含有 getter 相关的属性名称。与 MetaObject 判断类似。
getGetInvoker(name) name 的 getter 方法的 Invoker。
hasSetter(name) 判断是否有属性 name 或 name 的 setter 方法。与 MetaObject 判断类似。
getSetterNames() 获取含有 setter 相关的属性名称。与 MetaObject 判断类似。
getSetterType(name) 获取 setter 方法的参数类型。与 MetaObject 判断类似。
getSetInvoker(name) name 的 setter 方法的 Invoker。

3.4 MetaObject类

MetaObject 用于获取和设置对象的属性值

方法 说明
hasGetter(name) 判断是否有属性 name 或 name 的 getter 方法。
1. 若定义 userId,没定义 getUserId() 方法,hasGetter(“userId”) 则返回 true;
2. 若定义方法 getUserId1(),没定义属性 userId1,hasGetter(“userId1”) 则返回 true。
getGetterNames() 获取含有 getter 相关的属性名称。
1. 若定义 userId,没定义 getUserId() 方法,则 userId 会被返回;
2. 若定义方法 getUserId1(),没定义属性 userId1, 则 userId1 会被返回。
getGetterType(name) 获取 getter 方法的返回类型。
getValue(name) 获取属性值。
hasSetter(name) 判断是否有属性 name 或 name 的 setter 方法。
1. 若定义 userId,没定义 setUserId(userId) 方法,hasSetter(“userId”) 则返回 true;
2. 若定义方法 setUserId1(userId1),没定义属性 userId1,hasSetter(“userId1”) 则返回 true。
getSetterNames() 获取含有 setter 相关的属性名称。
1. 若定义 userId,没定义 setUserId(userId) 方法,则 userId 会被返回;
2. 若定义方法 setUserId1(userId1),没定义属性 userId1, 则 userId1 会被返回。
getSetterType(name) 获取 setter 方法的参数类型。
setValue(name,value) 设置属性值。

3.5 SystemMetaObject类

/**
 * @author Clinton Begin
 * 系统元对象
 */
public final class SystemMetaObject {
    
    
  /** 默认对象工厂 */
  public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
  /** 默认对象包装工厂 */
  public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
  /** 默认空元对象 */
  public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(new NullObject(), DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());

  private SystemMetaObject() {
    
    
    // Prevent Instantiation of Static Class
  }

  private static class NullObject {
    
    
  }

  public static MetaObject forObject(Object object) {
    
    
    return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
  }

}

MapperMethod、 BaseExecutor、 CachingExecutor、 DefaultResultSetHandler、 DefaultParameterHandler、Configuration中都是用MetaObject类

4 使用演示

Mybatis框架的源码中提供了丰富的测试案例演示反射工具中核心的工具类的使用方式, 下面我们简单演示几个,更多测试案例可以到源码中自行查看。
在这里插入图片描述

4.1 Reflector使用示例

class ReflectorTest {
    
    

  @Test
  void testGetSetterType() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertEquals(Long.class, reflector.getSetterType("id"));
  }

  @Test
  void testGetGetterType() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertEquals(Long.class, reflector.getGetterType("id"));
  }

  @Test
  void shouldNotGetClass() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    Reflector reflector = reflectorFactory.findForClass(Section.class);
    Assertions.assertFalse(reflector.hasGetter("class"));
  }

  interface Entity<T> {
    
    
    T getId();

    void setId(T id);
  }

  static abstract class AbstractEntity implements Entity<Long> {
    
    

    private Long id;

    @Override
    public Long getId() {
    
    
      return id;
    }

    @Override
    public void setId(Long id) {
    
    
      this.id = id;
    }
  }

  static class Section extends AbstractEntity implements Entity<Long> {
    
    
  }
 }

4.2 MetaClass使用示例

/*
 *    Copyright 2009-2022 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.domain.misc.RichType;
import org.apache.ibatis.domain.misc.generics.GenericConcrete;
import org.junit.jupiter.api.Test;

class MetaClassTest {
    
    

  @Test
  void shouldTestDataTypeOfGenericMethod() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(GenericConcrete.class, reflectorFactory);
    assertEquals(Long.class, meta.getGetterType("id"));
    assertEquals(Long.class, meta.getSetterType("id"));
  }

  @Test
  void shouldThrowReflectionExceptionGetGetterType() {
    
    
    try {
    
    
      ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
      MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
      meta.getGetterType("aString");
      org.junit.jupiter.api.Assertions.fail("should have thrown ReflectionException");
    } catch (ReflectionException expected) {
    
    
      assertEquals("There is no getter for property named \'aString\' in \'class org.apache.ibatis.domain.misc.RichType\'", expected.getMessage());
    }
  }

  @Test
  void shouldCheckGetterExistance() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertTrue(meta.hasGetter("richField"));
    assertTrue(meta.hasGetter("richProperty"));
    assertTrue(meta.hasGetter("richList"));
    assertTrue(meta.hasGetter("richMap"));
    assertTrue(meta.hasGetter("richList[0]"));

    assertTrue(meta.hasGetter("richType"));
    assertTrue(meta.hasGetter("richType.richField"));
    assertTrue(meta.hasGetter("richType.richProperty"));
    assertTrue(meta.hasGetter("richType.richList"));
    assertTrue(meta.hasGetter("richType.richMap"));
    assertTrue(meta.hasGetter("richType.richList[0]"));

    assertEquals("richType.richProperty", meta.findProperty("richType.richProperty", false));

    assertFalse(meta.hasGetter("[0]"));
  }

  @Test
  void shouldCheckSetterExistance() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertTrue(meta.hasSetter("richField"));
    assertTrue(meta.hasSetter("richProperty"));
    assertTrue(meta.hasSetter("richList"));
    assertTrue(meta.hasSetter("richMap"));
    assertTrue(meta.hasSetter("richList[0]"));

    assertTrue(meta.hasSetter("richType"));
    assertTrue(meta.hasSetter("richType.richField"));
    assertTrue(meta.hasSetter("richType.richProperty"));
    assertTrue(meta.hasSetter("richType.richList"));
    assertTrue(meta.hasSetter("richType.richMap"));
    assertTrue(meta.hasSetter("richType.richList[0]"));

    assertFalse(meta.hasSetter("[0]"));
  }

  @Test
  void shouldCheckTypeForEachGetter() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(String.class, meta.getGetterType("richField"));
    assertEquals(String.class, meta.getGetterType("richProperty"));
    assertEquals(List.class, meta.getGetterType("richList"));
    assertEquals(Map.class, meta.getGetterType("richMap"));
    assertEquals(List.class, meta.getGetterType("richList[0]"));

    assertEquals(RichType.class, meta.getGetterType("richType"));
    assertEquals(String.class, meta.getGetterType("richType.richField"));
    assertEquals(String.class, meta.getGetterType("richType.richProperty"));
    assertEquals(List.class, meta.getGetterType("richType.richList"));
    assertEquals(Map.class, meta.getGetterType("richType.richMap"));
    assertEquals(List.class, meta.getGetterType("richType.richList[0]"));
  }

  @Test
  void shouldCheckTypeForEachSetter() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(String.class, meta.getSetterType("richField"));
    assertEquals(String.class, meta.getSetterType("richProperty"));
    assertEquals(List.class, meta.getSetterType("richList"));
    assertEquals(Map.class, meta.getSetterType("richMap"));
    assertEquals(List.class, meta.getSetterType("richList[0]"));

    assertEquals(RichType.class, meta.getSetterType("richType"));
    assertEquals(String.class, meta.getSetterType("richType.richField"));
    assertEquals(String.class, meta.getSetterType("richType.richProperty"));
    assertEquals(List.class, meta.getSetterType("richType.richList"));
    assertEquals(Map.class, meta.getSetterType("richType.richMap"));
    assertEquals(List.class, meta.getSetterType("richType.richList[0]"));
  }

  @Test
  void shouldCheckGetterAndSetterNames() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals(5, meta.getGetterNames().length);
    assertEquals(5, meta.getSetterNames().length);
  }

  @Test
  void shouldFindPropertyName() {
    
    
    ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
    assertEquals("richField", meta.findProperty("RICHfield"));
  }

}

4.3 MetaObject使用示例

/*
 *    Copyright 2009-2022 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import static org.junit.jupiter.api.Assertions.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.domain.blog.Author;
import org.apache.ibatis.domain.blog.Section;
import org.apache.ibatis.domain.misc.CustomBeanWrapper;
import org.apache.ibatis.domain.misc.CustomBeanWrapperFactory;
import org.apache.ibatis.domain.misc.RichType;
import org.junit.jupiter.api.Test;

class MetaObjectTest {
    
    

  @Test
  void shouldGetAndSetField() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richField", "foo");
    assertEquals("foo", meta.getValue("richField"));
  }

  @Test
  void shouldGetAndSetNestedField() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richField", "foo");
    assertEquals("foo", meta.getValue("richType.richField"));
  }

  @Test
  void shouldGetAndSetProperty() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richProperty", "foo");
    assertEquals("foo", meta.getValue("richProperty"));
  }

  @Test
  void shouldGetAndSetNestedProperty() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richProperty", "foo");
    assertEquals("foo", meta.getValue("richType.richProperty"));
  }

  @Test
  void shouldGetAndSetMapPair() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richMap.key", "foo");
    assertEquals("foo", meta.getValue("richMap.key"));
  }

  @Test
  void shouldGetAndSetMapPairUsingArraySyntax() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richMap[key]", "foo");
    assertEquals("foo", meta.getValue("richMap[key]"));
  }

  @Test
  void shouldGetAndSetNestedMapPair() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richMap.key", "foo");
    assertEquals("foo", meta.getValue("richType.richMap.key"));
  }

  @Test
  void shouldGetAndSetNestedMapPairUsingArraySyntax() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richMap[key]", "foo");
    assertEquals("foo", meta.getValue("richType.richMap[key]"));
  }

  @Test
  void shouldGetAndSetListItem() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richList[0]", "foo");
    assertEquals("foo", meta.getValue("richList[0]"));
  }

  @Test
  void shouldGetAndSetNestedListItem() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    meta.setValue("richType.richList[0]", "foo");
    assertEquals("foo", meta.getValue("richType.richList[0]"));
  }

  @Test
  void shouldGetReadablePropertyNames() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    String[] readables = meta.getGetterNames();
    assertEquals(5, readables.length);
    for (String readable : readables) {
    
    
      assertTrue(meta.hasGetter(readable));
      assertTrue(meta.hasGetter("richType." + readable));
    }
    assertTrue(meta.hasGetter("richType"));
  }

  @Test
  void shouldGetWriteablePropertyNames() {
    
    
    RichType rich = new RichType();
    MetaObject meta = SystemMetaObject.forObject(rich);
    String[] writeables = meta.getSetterNames();
    assertEquals(5, writeables.length);
    for (String writeable : writeables) {
    
    
      assertTrue(meta.hasSetter(writeable));
      assertTrue(meta.hasSetter("richType." + writeable));
    }
    assertTrue(meta.hasSetter("richType"));
  }

  @Test
  void shouldSetPropertyOfNullNestedProperty() {
    
    
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    richWithNull.setValue("richType.richProperty", "foo");
    assertEquals("foo", richWithNull.getValue("richType.richProperty"));
  }

  @Test
  void shouldSetPropertyOfNullNestedPropertyWithNull() {
    
    
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    richWithNull.setValue("richType.richProperty", null);
    assertNull(richWithNull.getValue("richType.richProperty"));
  }

  @Test
  void shouldGetPropertyOfNullNestedProperty() {
    
    
    MetaObject richWithNull = SystemMetaObject.forObject(new RichType());
    assertNull(richWithNull.getValue("richType.richProperty"));
  }

  @Test
  void shouldVerifyHasReadablePropertiesReturnedByGetReadablePropertyNames() {
    
    
    MetaObject object = SystemMetaObject.forObject(new Author());
    for (String readable : object.getGetterNames()) {
    
    
      assertTrue(object.hasGetter(readable));
    }
  }

  @Test
  void shouldVerifyHasWriteablePropertiesReturnedByGetWriteablePropertyNames() {
    
    
    MetaObject object = SystemMetaObject.forObject(new Author());
    for (String writeable : object.getSetterNames()) {
    
    
      assertTrue(object.hasSetter(writeable));
    }
  }

  @Test
  void shouldSetAndGetProperties() {
    
    
    MetaObject object = SystemMetaObject.forObject(new Author());
    object.setValue("email", "test");
    assertEquals("test", object.getValue("email"));

  }

  @Test
  void shouldVerifyPropertyTypes() {
    
    
    MetaObject object = SystemMetaObject.forObject(new Author());
    assertEquals(6, object.getSetterNames().length);
    assertEquals(int.class, object.getGetterType("id"));
    assertEquals(String.class, object.getGetterType("username"));
    assertEquals(String.class, object.getGetterType("password"));
    assertEquals(String.class, object.getGetterType("email"));
    assertEquals(String.class, object.getGetterType("bio"));
    assertEquals(Section.class, object.getGetterType("favouriteSection"));
  }

  @Test
  void shouldDemonstrateDeeplyNestedMapProperties() {
    
    
    HashMap<String, String> map = new HashMap<>();
    MetaObject metaMap = SystemMetaObject.forObject(map);

    assertTrue(metaMap.hasSetter("id"));
    assertTrue(metaMap.hasSetter("name.first"));
    assertTrue(metaMap.hasSetter("address.street"));

    assertFalse(metaMap.hasGetter("id"));
    assertFalse(metaMap.hasGetter("name.first"));
    assertFalse(metaMap.hasGetter("address.street"));

    metaMap.setValue("id", "100");
    metaMap.setValue("name.first", "Clinton");
    metaMap.setValue("name.last", "Begin");
    metaMap.setValue("address.street", "1 Some Street");
    metaMap.setValue("address.city", "This City");
    metaMap.setValue("address.province", "A Province");
    metaMap.setValue("address.postal_code", "1A3 4B6");

    assertTrue(metaMap.hasGetter("id"));
    assertTrue(metaMap.hasGetter("name.first"));
    assertTrue(metaMap.hasGetter("address.street"));

    assertEquals(3, metaMap.getGetterNames().length);
    assertEquals(3, metaMap.getSetterNames().length);

    @SuppressWarnings("unchecked")
    Map<String,String> name = (Map<String,String>) metaMap.getValue("name");
    @SuppressWarnings("unchecked")
    Map<String,String> address = (Map<String,String>) metaMap.getValue("address");

    assertEquals("Clinton", name.get("first"));
    assertEquals("1 Some Street", address.get("street"));
  }

  @Test
  void shouldDemonstrateNullValueInMap() {
    
    
    HashMap<String, String> map = new HashMap<>();
    MetaObject metaMap = SystemMetaObject.forObject(map);
    assertFalse(metaMap.hasGetter("phone.home"));

    metaMap.setValue("phone", null);
    assertTrue(metaMap.hasGetter("phone"));
    // hasGetter returns true if the parent exists and is null.
    assertTrue(metaMap.hasGetter("phone.home"));
    assertTrue(metaMap.hasGetter("phone.home.ext"));
    assertNull(metaMap.getValue("phone"));
    assertNull(metaMap.getValue("phone.home"));
    assertNull(metaMap.getValue("phone.home.ext"));

    metaMap.setValue("phone.office", "789");
    assertFalse(metaMap.hasGetter("phone.home"));
    assertFalse(metaMap.hasGetter("phone.home.ext"));
    assertEquals("789", metaMap.getValue("phone.office"));
    assertNotNull(metaMap.getValue("phone"));
    assertNull(metaMap.getValue("phone.home"));
  }

  @Test
  void shouldNotUseObjectWrapperFactoryByDefault() {
    
    
    MetaObject meta = SystemMetaObject.forObject(new Author());
    assertTrue(!meta.getObjectWrapper().getClass().equals(CustomBeanWrapper.class));
  }

  @Test
  void shouldUseObjectWrapperFactoryWhenSet() {
    
    
    MetaObject meta = MetaObject.forObject(new Author(), SystemMetaObject.DEFAULT_OBJECT_FACTORY, new CustomBeanWrapperFactory(), new DefaultReflectorFactory());
    assertEquals(CustomBeanWrapper.class, meta.getObjectWrapper().getClass());

    // Make sure the old default factory is in place and still works
    meta = SystemMetaObject.forObject(new Author());
    assertNotEquals(CustomBeanWrapper.class, meta.getObjectWrapper().getClass());
  }

  @Test
  void shouldMethodHasGetterReturnTrueWhenListElementSet() {
    
    
    List<Object> param1 = new ArrayList<>();
    param1.add("firstParam");
    param1.add(222);
    param1.add(new Date());

    Map<String, Object> parametersEmulation = new HashMap<>();
    parametersEmulation.put("param1", param1);
    parametersEmulation.put("filterParams", param1);

    MetaObject meta = SystemMetaObject.forObject(parametersEmulation);

    assertEquals(param1.get(0), meta.getValue("filterParams[0]"));
    assertEquals(param1.get(1), meta.getValue("filterParams[1]"));
    assertEquals(param1.get(2), meta.getValue("filterParams[2]"));

    assertTrue(meta.hasGetter("filterParams[0]"));
    assertTrue(meta.hasGetter("filterParams[1]"));
    assertTrue(meta.hasGetter("filterParams[2]"));
  }

}

5、反射工具类在Mybatis框架中的应用

5.1 DefaultResultSetHandler

查询结果集的核心处理方法createResultObject()中有很多地方都使用了到了反射工具类

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.2 DefaultParameterHandler

  /**
   * 替换SQL语句中的占位符为实际传入的参数值的方法
   */
  @Override
  public void setParameters(PreparedStatement ps) {
    
    
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
    // 从BoundSql对象中获取到参数映射对象集合
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    if (parameterMappings != null) {
    
    
      for (int i = 0; i < parameterMappings.size(); i++) {
    
    
        // 依次取出parameterMapping对象
        ParameterMapping parameterMapping = parameterMappings.get(i);
        // 保证当前处理的parameterMapping对象都是输入参数
        if (parameterMapping.getMode() != ParameterMode.OUT) {
    
    
          Object value;
          // 获取当前处理的parameterMapping对象的属性名称
          String propertyName = parameterMapping.getProperty();
          // 如果BoundSql对象的附加参数对象中包含该属性名称, 直接从BoundSql对象的附加参数对象中获取到该属性KEY对应的值
          if (boundSql.hasAdditionalParameter(propertyName)) {
    
     // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
            // 如果ParameterObject为空,说明没有传值,值直接就为null
          } else if (parameterObject == null) {
    
    
            value = null;
            // 如果类型注册器中有该参数对象对应的类型处理器,则该参数取值就是parameterObject
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
    
    
            value = parameterObject;
            // 以上都不满足,就创建一个元数据对象,然后从元数据对象汇总通过属性获取到对应的取值
          } else {
    
    
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          // 获取当前parameterMapping对象的类型处理器
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          // 获取当前parameterMapping对象的JDBC数据类型
          JdbcType jdbcType = parameterMapping.getJdbcType();
          // 如果参数输入值为null并且数据库数据类型为null,就将jdbcType类型设置为OTHER类型
          if (value == null && jdbcType == null) {
    
    
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
    
    
            // 为什么这里是使用i + 1?
            // insert into t_user(name, age, gender, email) value(?, ?, ?, ?)
            // 因为解析出来的带占位的sql语法中的?参数的计数是从1开始的, 不是从0开始的
            // 调用typeHandler的替换参数的方法替换到SQL语句中目标位置上占位符上为输入的参数值
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
    
    
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

5.3 Configuration

在这里插入图片描述

反射在java项目的实践应用中是非常重要的,必须熟练掌握,很多成熟的开源框架中都已经封装了很多非常好的反射工具,我们在进行源码阅读时,可以将这些精华的部分进行搜集整理应用到自己的项目中,只看是学不会的,编程这个东西还是更注重实践,实践的多了,自然你就会自主的去学习和思考了。

猜你喜欢

转载自blog.csdn.net/qq_41865652/article/details/129778497