Mybatis MetaObject 淺析

前段时间做公司业务, 刚好遇到场景要动态获取Pojo类, 然后作一些运算, 再赋值到另一个类上, 立即想到用反射来解决, 但自己写的需要写一大堆代码, 而且自己感觉写得不是太好, 想着有没有第三方已经封装好的api可以用呢? 刚好想到 Mybatis是利用 MetaObject做ORM处理, 可以借来用用 (Mybatis的源码没白读哈)。用是用得挺爽, 但在想MetaObject是怎么做到可以像动态语言般来处理Pojo类呢? 因此决定去认真读一下它的源码。

先写一个示例看看:

package com.example.metdobjectanalysis.model;

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

-------

package com.example.metdobjectanalysis;

import com.example.metdobjectanalysis.model.Person;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MetdObjectAnalysisApplicationTests {

    @Test
    void getTest() {
        Person person = new Person();

        MetaObject metaObject = SystemMetaObject.forObject(person);
        String name = (String) metaObject.getValue("name");
        metaObject.setValue("name", "tom");
        System.out.println("The name is " + name);
        // 返回结果是 The name is Tom
    }
}
复制代码

代码很直观, 不用作太多解释, 现在的问题是:

  1. SystemMetaObject.forObject 里面做了什么?
  2. MetaObject 是怎么进行操作呢?

SystemMetaObject

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(NullObject.class, 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());
  }

}
复制代码

可以看出 SystemMetaObject是一个工厂, 它是只负责 MetaObject 的默认方式创造, 封装了它的构造方法, 可以看出创造 MetaObject 需要传入四个参数, 分别是要操作的对象, ObjectFactory, ObjectWrapperFactory 和 ReflectorFactory。

ObjectFactory

先看看ObjectFactory的接口:

/**
 * MyBatis uses an ObjectFactory to create all needed new Objects.
 *
 * @author Clinton Begin
 */
public interface ObjectFactory {

  /**
   * Sets configuration properties.
   * @param properties configuration properties
   */
  default void setProperties(Properties properties) {
    // NOP
  }

  /**
   * Creates a new object with default constructor.
   *
   * @param <T>
   *          the generic type
   * @param type
   *          Object type
   * @return the t
   */
  <T> T create(Class<T> type);

  /**
   * Creates a new object with the specified constructor and params.
   *
   * @param <T>
   *          the generic type
   * @param type
   *          Object type
   * @param constructorArgTypes
   *          Constructor argument types
   * @param constructorArgs
   *          Constructor argument values
   * @return the t
   */
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

  /**
   * Returns true if this object can have a set of other objects.
   * It's main purpose is to support non-java.util.Collection objects like Scala collections.
   *
   * @param <T>
   *          the generic type
   * @param type
   *          Object type
   * @return whether it is a collection or not
   * @since 3.1.0
   */
  <T> boolean isCollection(Class<T> type);

}
复制代码

这接口定义了它是负责创建对象的, 再去看一下 DefaultObjectFactory 是怎么创建对象的:

public class DefaultObjectFactory implements ObjectFactory, Serializable {

  private static final long serialVersionUID = -8855120656740914948L;

  @Override
  public <T> T create(Class<T> type) {
    return create(type, null, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    Class<?> classToCreate = resolveInterface(type);
    // we know types are assignable
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }

  private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        try {
          return constructor.newInstance();
        } catch (IllegalAccessException e) {
          if (Reflector.canControlMemberAccessible()) {
            constructor.setAccessible(true);
            return constructor.newInstance();
          } else {
            throw e;
          }
        }
      }
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
      try {
        return constructor.newInstance(constructorArgs.toArray(new Object[0]));
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance(constructorArgs.toArray(new Object[0]));
        } else {
          throw e;
        }
      }
    } catch (Exception e) {
      String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
          .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
      String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
          .stream().map(String::valueOf).collect(Collectors.joining(","));
      throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }

  protected Class<?> resolveInterface(Class<?> type) {
    Class<?> classToCreate;
    if (type == List.class || type == Collection.class || type == Iterable.class) {
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      classToCreate = HashMap.class;
    } else if (type == SortedSet.class) { // issue #510 Collections Support
      classToCreate = TreeSet.class;
    } else if (type == Set.class) {
      classToCreate = HashSet.class;
    } else {
      classToCreate = type;
    }
    return classToCreate;
  }

  @Override
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }

}
复制代码

可以得知它的主要构造对象的方法是 public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs):

@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  Class<?> classToCreate = resolveInterface(type);
  // we know types are assignable
  return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
复制代码

resolveInterface负责处理接口, 把它转成相应的实现类:

protected Class<?> resolveInterface(Class<?> type) {
  Class<?> classToCreate;
  if (type == List.class || type == Collection.class || type == Iterable.class) {
    classToCreate = ArrayList.class;
  } else if (type == Map.class) {
    classToCreate = HashMap.class;
  } else if (type == SortedSet.class) { // issue #510 Collections Support
    classToCreate = TreeSet.class;
  } else if (type == Set.class) {
    classToCreate = HashSet.class;
  } else {
    classToCreate = type;
  }
  return classToCreate;
}
复制代码

instantiateClass则把类创建, 实现很简单, 先看有没有需要传入构造方法的参数, 没有就表示调用无参构造方法, 如果有就调用相应的构造方法:

private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  try {
    Constructor<T> constructor;
    if (constructorArgTypes == null || constructorArgs == null) {
      constructor = type.getDeclaredConstructor();
      try {
        return constructor.newInstance();
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance();
        } else {
          throw e;
        }
      }
    }
    constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
    try {
      return constructor.newInstance(constructorArgs.toArray(new Object[0]));
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        constructor.setAccessible(true);
        return constructor.newInstance(constructorArgs.toArray(new Object[0]));
      } else {
        throw e;
      }
    }
  } catch (Exception e) {
    String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
        .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
    String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
        .stream().map(String::valueOf).collect(Collectors.joining(","));
    throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
  }
}
复制代码

这里可以注意一下最后的错误处理, 利用了Optional 来做空值的错误处理。

ObjectWrapperFactory

SystemMetaObject创造的 MetaObject 是没有包装类的。

扫描二维码关注公众号,回复: 13694546 查看本文章

ReflectorFactory

public interface ReflectorFactory {

  boolean isClassCacheEnabled();

  void setClassCacheEnabled(boolean classCacheEnabled);

  Reflector findForClass(Class<?> type);
}
复制代码

看接口定义, 可以推测两件事, 一是里面会用到缓存, 二是利用 findForClass 找到反射器, 看一下 DefaultReflectorFactory:

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();

  public DefaultReflectorFactory() {
  }

  @Override
  public boolean isClassCacheEnabled() {
    return classCacheEnabled;
  }

  @Override
  public void setClassCacheEnabled(boolean classCacheEnabled) {
    this.classCacheEnabled = classCacheEnabled;
  }

  @Override
  public Reflector findForClass(Class<?> type) {
    if (classCacheEnabled) {
      // synchronized (type) removed see issue #461
      return reflectorMap.computeIfAbsent(type, Reflector::new);
    } else {
      return new Reflector(type);
    }
  }
}
复制代码

里面内容不多, 由于 classCacheEnabled为true, 所以一定会调 reflectMap 把反射器 Reflector 存起来 , 重点是要关注 Reflector, 可以猜出它的 Mybatis 做反射处理的主角:

/**
 * This class represents a cached set of class definition information that
 * allows for easy mapping between property names and getter/setter methods.
 *
 * @author Clinton Begin
 */
public class Reflector {

  private final Class<?> type;
  private final String[] readablePropertyNames;
  private final String[] writablePropertyNames;
  private final Map<String, Invoker> setMethods = new HashMap<>();
  private final Map<String, Invoker> getMethods = new HashMap<>();
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  private Constructor<?> defaultConstructor;

  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

  public Reflector(Class<?> clazz) {
    type = clazz;
    addDefaultConstructor(clazz);
    addGetMethods(clazz);
    addSetMethods(clazz);
    addFields(clazz);
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    writablePropertyNames = setMethods.keySet().toArray(new String[0]);
    for (String propName : readablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }
}
复制代码

源码太多我不全部放上来, 详细读者可以自己看, 我只放上构造方法相关的源码, 已经足够说明它是干什么的, 简介已经说明它是做属性名和getter/setter方法的映射。

addDefaultConstructor 会去找类的构造方法, 如果没有参数的则添加到赋值给 defaultConstructor, addGetMethodsaddSetMethods类似, 根据方法名称判断是否为getter/setter, 与此同时, 也做相应的特殊处理。

为什么要用 reflectorMap? 这样就可以复用之前创建的Reflector? 为什么要用ConcurrentHashMap? 因为服务器一般是多綫程环境, 用ConcurrentHashMap可以确保获取和创建都是原子性操作。

MetaObject

终于要讲到今天的主角 MetaObject, 先看源码:

public class MetaObject {

  private final Object originalObject;
  private final ObjectWrapper objectWrapper;
  private final ObjectFactory objectFactory;
  private final ObjectWrapperFactory objectWrapperFactory;
  private final ReflectorFactory reflectorFactory;

  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;

    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

  public Object getValue(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return null;
      } else {
        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());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        if (value == null) {
          // don't instantiate child path if value is null
          return;
        } else {
          metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
        }
      }
      metaValue.setValue(prop.getChildren(), value);
    } else {
      objectWrapper.set(prop, value);
    }
  }

  public MetaObject metaObjectForProperty(String name) {
    Object value = getValue(name);
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }
}
复制代码

首先可以看出它是一个代理类, 只是基于原本的类作了功能加强, 然后可以看到它的方法中大量调用 ObjectWrapper, 其实 MetaObject 只是作一些前置处理, 真正操作它的是 ObjectWrapper。先看看 ObjectWrapper接口:

public interface ObjectWrapper {

  Object get(PropertyTokenizer prop);

  void set(PropertyTokenizer prop, Object value);

  String findProperty(String name, boolean useCamelCaseMapping);

  String[] getGetterNames();

  String[] getSetterNames();

  Class<?> getSetterType(String name);

  Class<?> getGetterType(String name);

  boolean hasSetter(String name);

  boolean hasGetter(String name);

  MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

  boolean isCollection();

  void add(Object element);

  <E> void addAll(List<E> element);

}
复制代码
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
  this.originalObject = object;
  this.objectFactory = objectFactory;
  this.objectWrapperFactory = objectWrapperFactory;
  this.reflectorFactory = reflectorFactory;

  if (object instanceof ObjectWrapper) {
    this.objectWrapper = (ObjectWrapper) object;
  } else if (objectWrapperFactory.hasWrapperFor(object)) {
    this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
  } else if (object instanceof Map) {
    this.objectWrapper = new MapWrapper(this, (Map) object);
  } else if (object instanceof Collection) {
    this.objectWrapper = new CollectionWrapper(this, (Collection) object);
  } else {
    this.objectWrapper = new BeanWrapper(this, object);
  }
}
复制代码

因为我们传入的是 DefaultObjectWrapperFactory , 所以它最后会调用 BeanWrapper:

public class BeanWrapper extends BaseWrapper {

  private final Object object;
  private final MetaClass metaClass;

  public BeanWrapper(MetaObject metaObject, Object object) {
    super(metaObject);
    this.object = object;
    this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
  }
  ...
}
复制代码

ReflectorFactory传入MetaClass可以看出, 它是处理反射方法的。

getValue/setValue

因为这里会涉及不同情况, 所以要分情况讲解。

先谈讨最简单的情况, 就是只对基本类 (如 String, Integer)作处理的情况:

基本类情况

我再一次把示例代码贴上:

package com.example.metdobjectanalysis.model;

public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

-------

package com.example.metdobjectanalysis;

import com.example.metdobjectanalysis.model.Person;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MetdObjectAnalysisApplicationTests {

    @Test
    void contextLoads() {
    }

    @Test
    void getTest() {
        Person person = new Person();

        MetaObject metaObject = SystemMetaObject.forObject(person);
        String name = (String) metaObject.getValue("name");
        metaObject.setValue("name", "tom");
        System.out.println("The name is " + name);
        // 返回结果是 The name is Tom
    }
}
复制代码

先看MetaObjectsetValue 到底做了什么:

public void setValue(String name, Object value) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      if (value == null) {
        // don't instantiate child path if value is null
        return;
      } else {
        metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
      }
    }
    metaValue.setValue(prop.getChildren(), value);
  } else {
    objectWrapper.set(prop, value);
  }
}
复制代码

PropertyTokenizer是指传入的属性名作解析, 因为传入的属性名可能是集合, 也可能是嵌套类型, 因此要做解析处理。 由于现在的情况是单个属性名, 所以直接走到 objectWrapper.set(prop, value), 然后走到 BeanWrappersetBeanProperty方法:

private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
  try {
    Invoker method = metaClass.getSetInvoker(prop.getName());
    Object[] params = {value};
    try {
      method.invoke(object, params);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  } catch (Throwable t) {
    throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
}
复制代码

看代码可以得知, 就是获取类型的setter, 然后调用。getValue也是同理, 就不看源码了。

集合类情况

先看一下例子:

public class Person {
    private String name;

    private List<String> friends;

    public Person(String name) {
        this.name = name;
        this.friends = new ArrayList<>(10);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getFriends() {
        return friends;
    }

    public void setFriends(int index, String friend) {
        this.friends.set(index, friend);
    }
}
复制代码
@Test
void collectionTest() {
    Person person = new Person("Mary");
    person.getFriends().add("Johnson");

    MetaObject metaObject = SystemMetaObject.forObject(person);
    metaObject.setValue("friends[0]", "Peter");
    String friendName = (String) metaObject.getValue("friends[0]");
    System.out.println("The friend's name is " + friendName);
    // 结果是 The friend's name is Peter
}
复制代码

如果是集合类, 流程是怎么走呢? 这次就要用到 PropertyTokenizer:

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  private String name;
  private final String indexedName;
  private String index;
  private final String children;

  public PropertyTokenizer(String 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;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }

  public String getName() {
    return name;
  }

  public String getIndex() {
    return index;
  }

  public String getIndexedName() {
    return indexedName;
  }

  public String getChildren() {
    return children;
  }

  @Override
  public boolean hasNext() {
    return children != null;
  }

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
  }
}
复制代码

看一下构造方法, 如果解析到是集合类, 就把索引提取出来。然后又到了BeanWrapper.setValue方法:

@Override
public void set(PropertyTokenizer prop, Object value) {
  if (prop.getIndex() != null) {
    Object collection = resolveCollection(prop, object);
    setCollectionValue(prop, collection, value);
  } else {
    setBeanProperty(prop, object, value);
  }
}
复制代码

这次要走prop.getIndex() !== null的流程:

protected Object resolveCollection(PropertyTokenizer prop, Object object) {
  if ("".equals(prop.getName())) {
    return object;
  } else {
    return metaObject.getValue(prop.getName());
  }
}
复制代码

先获取集合类, 然后调用setCollectionValue来赋值:

protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
  if (collection instanceof Map) {
    ((Map) collection).put(prop.getIndex(), value);
  } else {
    int i = Integer.parseInt(prop.getIndex());
    if (collection instanceof List) {
      ((List) collection).set(i, value);
    } else if (collection instanceof Object[]) {
      ((Object[]) collection)[i] = value;
    } else if (collection instanceof char[]) {
      ((char[]) collection)[i] = (Character) value;
    } else if (collection instanceof boolean[]) {
      ((boolean[]) collection)[i] = (Boolean) value;
    } else if (collection instanceof byte[]) {
      ((byte[]) collection)[i] = (Byte) value;
    } else if (collection instanceof double[]) {
      ((double[]) collection)[i] = (Double) value;
    } else if (collection instanceof float[]) {
      ((float[]) collection)[i] = (Float) value;
    } else if (collection instanceof int[]) {
      ((int[]) collection)[i] = (Integer) value;
    } else if (collection instanceof long[]) {
      ((long[]) collection)[i] = (Long) value;
    } else if (collection instanceof short[]) {
      ((short[]) collection)[i] = (Short) value;
    } else {
      throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
    }
  }
}
复制代码

代码看起来好多, 做的无非是判断到底是什么集合类, 调用相应的方法来赋值。

嵌套类情况

终于要谈讨最複杂的情况, 又看一个例子:

public class Student {
    private Person person;

    private int id;

    public Student(int id, String name) {
        this.id = id;
        this.person = new Person(name);
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
复制代码
@Test
void nestTest() {
    Student student = new Student(11, "Tom");

    MetaObject metaObject = SystemMetaObject.forObject(student);
    metaObject.setValue("person.name", "Peter");
    String name = (String) metaObject.getValue("person.name");
    System.out.println("The student name is " + name);
    // 结果是 The student name is Peter
}
复制代码

这次PropertyTokenizerchildren了:

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  private String name;
  private final String indexedName;
  private String index;
  private final String children;

  public PropertyTokenizer(String 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;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }
...
  public String getChildren() {
    return children;
  }

@Override
public boolean hasNext() {
  return children != null;
}

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }
}
复制代码

PropertyTokenizer, 把.前的属性赋值给name, .后的属性给children, 如果对它做遍历操作, 则传入children, 生成新的 PropertyTokenizer

然后接下来有递归操作, 有点绕, 做好准备哈。

我把setValue的源码再贴上一次:

public void setValue(String name, Object value) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      if (value == null) {
        // don't instantiate child path if value is null
        return;
      } else {
        metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
      }
    }
    metaValue.setValue(prop.getChildren(), value);
  } else {
    objectWrapper.set(prop, value);
  }
}
复制代码

现在因为有children, 所以会走prop.hasNext的流程, 进入MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());

public MetaObject metaObjectForProperty(String name) {
  Object value = getValue(name);
  return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
}
复制代码

看到它调用getValue, 然后再生成一个生的MetaObject对象, 注意除了原对象变了, 其馀三个参数是没有变化。看一看getValue的源码:

public Object getValue(String name) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return null;
    } else {
      return metaValue.getValue(prop.getChildren());
    }
  } else {
    return objectWrapper.get(prop);
  }
}
复制代码

setValue很类似, 因为这里只传入name, 把它解析后, 是没有children, 所以就直接走objectWrapper.get(prop);。然后就到metaValue.setValue(prop.getChildren(), value);, 生成的新的MetaObject再一次调用setValue, 只是这次传入的是children, 这意味着它会一直调用, 直接prop没有children为止, setValue方法才会走到objectWrapper.set(prop, value)

person.name作例子走一次流程就更加明白了。进入setValue, PropertyTokenizer作解析, 结果如下图所示:

propertyTokenizer.png

因为有children, 所以要走prop.hasNext流程, 进入metaObjectForProperty, 传入参数person去调用getValue, 最后获取Person对象, 生成新的MetaObject对象:

metaObject.png

基于新的MetaObject对象, 再一次调用setValue, 传入children, 也就是 name, 因此是:

recursiveSetValue.png

因为这次没有children, 所以直接走objectWrapper.set(prop, value);, 完成赋值。

整个 MetaObject 的基本操作已经讲解完了, 其他操作基本也差不多。

猜你喜欢

转载自juejin.im/post/7070340201423306759
今日推荐