MyBatis印象阅读之反射工具MetaObject
2019-07-25 本文已影响0人
向光奔跑_
在上一节中,我们介绍了关于反射相关的TypeParameterResolver和MetaClass,今日来学习剩下的MetaObject
可能大家已经注意到,我们上节中的MetaClass和本节中的MetaObject有点相像,它们之间是否会有关联?没错,如果说MetaClass是类的元信息的,那么MetaObject就是针对实例的。
1.MetaObject类学习
按照之前的学习方法,我们继续从一个Test Demo中来进行开始:
//MetaObjectTest
@Test
void shouldGetAndSetField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richField", "foo");
assertEquals("foo", meta.getValue("richField"));
}
其中RichType为:
public class RichType {
private RichType richType;
private String richField;
private String richProperty;
private Map richMap = new HashMap();
private List richList = new ArrayList() {
{
add("bar");
}
};
//其他是属性的get,set方法
}
上述中我们有一个方法我们还未接触过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());
}
}
注意,最关键的高潮来了
//MetaObject
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
if (object == null) {
return SystemMetaObject.NULL_META_OBJECT;
} else {
return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
}
/**
* 注意这里的构造函数是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) {
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);
}
}
这里引入了BeanWrapper,我们来进入分析下。
1.1 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());
}
}
整体的我们都熟悉了一遍,那么我们回到最初的起点:
@Test
void shouldGetAndSetField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richField", "foo");
assertEquals("foo", meta.getValue("richField"));
}
这里调用的setValue方法我们来看下源码。
1.2 MetaObject的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);
}
}
这里我们又看到了PropertyTokenizer,那就说明这里肯定又跟递归有关。
这里整理下逻辑可以帮助大家阅读
- 首先判断传参name是否存在递归,如果不存在则直接调用objectWrapper.set(prop, value);赋值
- 如果存在递归,使用PropertyTokenizer解析,然后是通过metaObjectForProperty(prop.getIndexedName());获取实例下的属性实例,判断是否为SystemMetaObject.NULL_META_OBJECT,如果是,则判断要赋值的value是否为空,如果是空则直接返回,不用继续赋值,如果不是,通过 objectWrapper.instantiatePropertyValue(name, prop, objectFactory)初始化创建属性实例
- 最后递归到最后一层属性时,通过 metaValue.setValue(prop.getChildren(), value)赋值
接下来我们进入metaObjectForProperty方法:
public MetaObject metaObjectForProperty(String name) {
Object value = getValue(name);
return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
}
再来进入看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);
}
}
再来看instantiatePropertyValue方法:
/**
* 初始化属性
*/
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
MetaObject metaValue;
Class<?> type = getSetterType(prop.getName());
try {
Object newObject = objectFactory.create(type);
metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
set(prop, newObject);
} catch (Exception e) {
throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);
}
return metaValue;
}
这里的逻辑大致就是创建实例里的某个属性的实例化。可能会有点绕。。这部分的代码强力建议调试下MetaObjectTest的shouldGetAndSetNestedField测试方法。
最后是 objectWrapper.set(prop, value)我们来看下代码:
@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);
}
}
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);
}
}
逻辑也很清晰,就是调用反射给实例属性赋值。
2.今日总结
今天我们介绍了MetaObject设置属性的过程,从中又涉及到了递归操作,希望大家可以通过调试并结合讲解来分析这块代码。