Mybatis 源码学习-反射工具(ObjectWrapper & MetaObject)
Posted 凉茶方便面
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis 源码学习-反射工具(ObjectWrapper & MetaObject)相关的知识,希望对你有一定的参考价值。
历史文章:
Mybatis 源码学习(6)-反射工具(MetaClass)
MetaClass 可以通过反射来解析类级别类型信息,而 ObjectWrapper 是对对象的包装,可以通过字符串操作和查询对象的属性。ObjectWrapper 类继承关系如下,它提供了 BaseWrapper、BeanWrapper、MapWrapper 和 CollectionWrapper。BaseWrapper 提供集合类型解析的抽象方法,BeanWrapper 提供普通 Bean 的 get、set 方法,MapWrapper 提供 Map 类型的 put 和 get 方法,CollectionWrapper 提供集合的 add 和 addAll 方法。
ObjectWrapper
ObjectWrapper 的接口定义如下:
public interface ObjectWrapper
// 获取指定的属性
// 如果封装的是普通的 Bean 对象,则调用对应的 get 方法
// 如果封装的是集合对象,则返回对应下标的 value
// 如果封装的是 Map 对象,则返回 key 对应的 value
Object get(PropertyTokenizer prop);
// 设置指定的属性值
// 如果封装的是普通的 Bean 对象,则调用对应的 set 方法
// 如果封装的是集合对象,则设置对应下标的 value
// 如果封装的是 Map 对象,则设置 key 对应的 value
void set(PropertyTokenizer prop, Object value);
// 查找属性表达式指定的属性
// useCamelCaseMapping 表示是否忽略表达式中的下划线
String findProperty(String name, boolean useCamelCaseMapping);
// 获取可读属性的名称集合
String[] getGetterNames();
// 获取可写属性的名称集合
String[] getSetterNames();
// 解析属性表达式指定的属性对应的 set 方法的参数类型
Class<?> getSetterType(String name);
// 解析属性表达式指定的属性对应的 get 方法的返回值
Class<?> getGetterType(String name);
// 判断属性表达式指定属性是否有 set/get 方法
boolean hasSetter(String name);
boolean hasGetter(String name);
// 为属性表达式指定的属性创建相应的 MetaObject 对象
MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);
// 判断封装对象是否是集合
boolean isCollection();
// 向集合中添加元素,调用 Collection.add 方法
void add(Object element);
// 向集合中添加一批元素,调用 Collection.addAll 方法
<E> void addAll(List<E> element);
ObjectWrapperFactory 负责创建 ObjectWrapper,系统默认提供了 DefaultObjectWrapperFactory,但是该默认工厂类不提供任何实现,仅抛出异常。在实际使用时,可以通过配置 mybatis-config.xml 在配置中设置自定义的 ObjectWrapperFactory。
BaseWrapper
BaseWrapper 是 ObjectWrapper 的子类(抽象类),它封装了 MetaObject,并且提供三个集合类型的操作方法供子类使用:resolveCollection、getCollectionValue、setCollectionValue。
BaseWrapper.resolveCollection 方法会调用 MetaObject.getValue 解析属性表达式对应的属性(不过它一般被用来解析集合类型的属性,它能兼容普通 Bean)。
BaseWrapper.getCollectionValue 和 BaseWrapper.setCollectionValue 方法类似,它们能够解析 Map、List、数组,这三种集合类型的对象,并能够根据下标操作对应的集合中的元素。
protected Object getCollectionValue(PropertyTokenizer prop, Object collection)
if (collection instanceof Map) // 集合是 Map 类型,index 是 key
return ((Map) collection).get(prop.getIndex());
else
int i = Integer.parseInt(prop.getIndex()); // 其他集合类型,index 是数值下标
if (collection instanceof List) // 确认集合的类型
return ((List) collection).get(i); // 按照下标获取对应下标元素的值
else if (collection instanceof Object[])
return ((Object[]) collection)[i];
else if (collection instanceof char[])
return ((char[]) collection)[i];
else if (collection instanceof boolean[])
return ((boolean[]) collection)[i];
else if (collection instanceof byte[])
return ((byte[]) collection)[i];
else if (collection instanceof double[])
return ((double[]) collection)[i];
else if (collection instanceof float[])
return ((float[]) collection)[i];
else if (collection instanceof int[])
return ((int[]) collection)[i];
else if (collection instanceof long[])
return ((long[]) collection)[i];
else if (collection instanceof short[])
return ((short[]) collection)[i];
else
throw new ReflectionException(“…”);
BeanWrapper
BeanWrapper 继承了 BaseWrapper,它封装了实际的 JavaBean 对象、该对象的 MetaClass、该对象的 MetaObject。除了类级别上的 findProperty、getGetterNames、getSetterNames、getSetterType、getGetterType、hasSetter、hasGetter方法外,BeanWrapper 还包含三个对象级别的操作方法:get、set、instantiatePropertyValue。
BeanWrapper.get、BeanWrapper.set 方法可以用来根据属性表达式获取和设置相应的属性值。
// 获取属性表达式对应的值
public Object get(PropertyTokenizer prop)
// 如果存在下标信息,则表示该表达式是集合类型
if (prop.getIndex() != null)
// 通过 MetaObject.getValue 方法获取 object 对象中的指定集合属性;
// 实际上 MetaObject.getValue 又重新调用了该方法,
// 由于重新调用时不存在下标,则会直接调用 getBeanProperty 去解析属性
Object collection = resolveCollection(prop, object);
// 按照下标获取元素
return getCollectionValue(prop, collection);
else
// 不存在索引,直接获取 Bean 属性
// 直接调用属性的 Invoker.invoke,即可能存在 get 方法或者 Field 本身
return getBeanProperty(prop, object);
private Object getBeanProperty(PropertyTokenizer prop, Object object)
try
// 根据属性名称,查找 Reflector.getMethods 集合中相应的 GetFieldinvoker 或 Methodinvoker
Invoker method = metaClass.getGetInvoker(prop.getName());
try
// 通过反射获取属性值
return method.invoke(object, NO_ARGUMENTS);
catch (Throwable t)
throw ExceptionUtil.unwrapThrowable(t);
catch (RuntimeException e)
throw e;
catch (Throwable t)
throw new ReflectionException(“…”);
BeanWrapper.instantiatePropertyValue 可以创建属性表达式指定的属性实例(只能是该对象直接引用的属性),同时创建该实例对应的 MetaObject。
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
MetaObject metaValue;
Class<?> type = getSetterType(prop.getName()); // 获取 getter 的返回值类型,即属性的类型
try
Object newObject = objectFactory.create(type); // 构造一个属性的实例
// 创建该实例的 MetaObject 以便后续通过 MetaObject 操作对象
metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
// 将属性实例设置至对象中
set(prop, newObject);
catch (Exception e)
throw new ReflectionException(“…”);
return metaValue;
MapWrapper
MapWrapper 是对 Map<String, Object> 的封装,它提供的 get、set 方法都是针对 key 做操作的。
CollectionWrapper
CollectionWrapper 是对 Collection 的封装,它不提供 get、set 方法,但是提供针对集合的 add 和 addAll 方法用于添加元素。
MetaObject
MetaObject 是对 ObjectWrapper 的封装,它提供实际对象的 getValue/setValue 方法,它的内部实现均依赖 ObjectWrapper。MetaObject 包含以下字段:
private final Object originalObject; // 原始 JavaBean 对象
private final ObjectWrapper objectWrapper; // 原始 JavaBean 对象对应的 ObjectWrapper
private final ObjectFactory objectFactory; // 负责实例化 originalObject 的 工厂对象
private final ObjectWrapperFactory objectWrapperFactory; // 负责创建ObjectWrapper的工厂对象
private final ReflectorFactory reflectorFactory; // 用于创建并缓存 Reflector 对象的工厂对象
MetaObject 的初始化需要传入原始对象、对象工厂 ObjectFactory 等,并在构造器内完成 ObjectWrapper 的初始化。
// private 修饰,避免外部创建对象
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) // 如果原始对象已经是 ObjectWrapper 对象,则直接使用
this.objectWrapper = (ObjectWrapper) object;
else if (objectWrapperFactory.hasWrapperFor(object))
// 若 ObjectWrapperFactory 能够为该原始对象创建对应的 ObjectWrapper 对象,则优先使用 ObjectWrapperFactory
// 默认的 DefaultObjectWrapperFactory.hasWrapperFor 返回值是 false 因此不能被使用
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
else if (object instanceof Map)
// 处理 Map 类型
this.objectWrapper = new MapWrapper(this, (Map) object);
else if (object instanceof Collection)
// 处理 Collection 类型
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
else
// 如果是普通 JavaBean,则创建 BeanWrapper
this.objectWrapper = new BeanWrapper(this, object);
// 静态工厂方法
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory)
if (object == null)
// 若 object 为 null ,则返回 SystemMetaObject .NULL_META_OBJECT 作为 null 对象
return SystemMetaObject.NULL_META_OBJECT;
else
return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
MetaObject 和 ObjectWrapper 中关于类级别的方法,例如 hasGetter、hasSetter、findProperty 等方法,都是直接调用 MetaClass 的对应方法实现的。而 MetaObject 关于对象的方法,例如 getValue、setValue 都是调用 ObjectWrapper 的方法实现的。
public Object getValue(String name)
// 解析属性表达式
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) // 处理子表达式
// 根据解析后的表达式创建 MetaObject
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return null;
else
return metaValue.getValue(prop.getChildren()); // 递归处理子表达式
else
return objectWrapper.get(prop); // 通过 ObjectWrapper 获取指定的属性(递归出口)
public MetaObject metaObjectForProperty(String name)
Object value = getValue(name); // 获取指定的属性
// 创建属性对应的 MetaObject
return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
如果存在以下类结构:
public class A
List<B> lists;
public class B
private String name;
以 metaObject.getValue("lists[0].name”)
为例,其中 metaObject 是对象 A 的一个实例对应的 MetaObject 对象:
- 调用
metaObject.getValue
将属性占位符解析为name = lists,indexName= lists[0],children = name
; - 调用 metaObjectForProperty 处理表达式
lists[0]
,通过间接调用 metaObject.getValue -> objectWrapper.get,会实际调用BeanWrapper.get
方法,解析集合类型对象,之后触发 resolveCollection 和 getCollectionValue 解析集合中的元素; - 得到对象 B 后,继续解析表达式 name,即调用表示 B 对象的
metaValue.getValue(“name”)
的属性值。
MetaObject.setValue 的逻辑和 MetaObject.getValue 的逻辑一致,但是如果需要设置的值不为空,会通过 BeanWrapper.instantiatePropertyValue 创建路径上的空对象(但是如果使用下标指定集合对象,则无法创建对应下标指向的对象)。BeanWrapper.instantiatePropertyValue 内部使用 DefaultObjectFactory.create 方法通过反射创建对象:
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
MetaObject metaValue;
// 获取属性 getter 方法的返回值类型
Class<?> type = getSetterType(prop.getName());
try
// 通过反射创建属性对象
Object newObject = objectFactory.create(type);
// 创建对象对应的 MetaObject
metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
// 将创建后的对象设置到对应的属性或集合中
set(prop, newObject);
catch (Exception e)
throw new ReflectionException(“…”);
return metaValue;
总结
ObjectWrapper 和 MetaObject 都是对对象的封装,ObjectWrapper 是一系列类,它提供对 JavaBean、Map、Collection 实例的操作封装,能够很方便的操作这些类型的属性、元素。MetaObject 是对 ObjectWrapper 的封装,它可以实现对任意类型的对象,通过属性表达式直接操作,而无需明确实例化对象。
参考文档:《Mybatis 技术内幕》
本文的基本脉络参考自《Mybatis 技术内幕》,编写文章的原因是希望能够系统地学习 Mybatis 的源码,但是如果仅阅读源码或者仅从官方文档很难去系统地学习,因此希望参考现成的文档,按照文章的脉络逐步学习。
欢迎关注我的公众号:我的搬砖日记,我会定时分享自己的学习历程。
以上是关于Mybatis 源码学习-反射工具(ObjectWrapper & MetaObject)的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis 源码学习-反射工具(TypeParameterResolver)
Mybatis 源码学习-反射工具(ObjectWrapper & MetaObject)