反射包解析
概述
mybatis反射包,提供了反射相关的工具,为啥要提供这些工具呢,java不是已经提供反射的功能了吗?
java反射虽然已经很强大,但是api偏底层,要想使用好可能会需要大量重复代码,可能使用不当也会产生性能问题,因此mybatis提供反射包提炼、封装、增强反射api,让上层应用用的更舒心。
包内容:
接下来会挑重点的类讲解下原理。
Invoker
invoker单独有一个子包,概念比较独立,也比较简单,代表执行器。包装了Method、Field的执行
Invoker定义:
java">public interface Invoker {
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
Class<?> getType();
}
主要定义了一个invoke方法,和Method.invoke几乎一样,这里做了抽象主要是把Field给包了进来。
GetFieldInvoker的invoke实现为 field.get(target,arg)
SetFieldInvoker的invoke实现为 field.set(target,arg)
factory
这里的工厂子包只包含了ObjectFactory和其实现类DefaultObjectFactory。
java">public interface ObjectFactory {
default void setProperties(Properties properties) {
// NOP
}
<T> T create(Class<T> type);
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
<T> boolean isCollection(Class<T> type);
}
就是通用的对象创建工厂,DefaultObjectFactory就是用构造函数去实例化对象,比较简单。
property
这个子包主要提供对类属性的反射解析工具。重点是PropertyTokenizer,意思是属性分隔解析器。
解析格式例如:order[0].item[name].firstName这样的表达式,有点类似json表达式,mybatis通过此类提供了表达式解析的能力,在处理嵌套属性时更加方便和通用。
java">public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
/**
* 当前属性
*/
private String name;
/**
* 当前完整分词
*/
private final String indexedName;
/**
* 索引值
* 如果是数组[0],则是0
* 如果是map[key],则是key、
*/
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);
}
}
@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.");
}
PropertyTokenizer使用了迭代器模式实现了递归解析子串,挺巧妙,之后有类似递归的需求可以借鉴一下,代码简单清晰。
数据:order[0].item[name].firstName
解析结果:
name=orde
indexedName=order[0]
index=0
children=item[name].firstName
结果简单清晰明了,有相关场景可以直接使用。
Reflector
java">public class Reflector {
/**
* 对应的类
*/
private final Class<?> type;
/**
* 可读的属性名集合
*/
private final String[] readablePropertyNames;
/**
* 可写的属性名集合
*/
private final String[] writablePropertyNames;
/**
* 所有set方法,
*/
private final Map<String, Invoker> setMethods = new HashMap<>();
/**
* 所有get方法
*/
private final Map<String, Invoker> getMethods = new HashMap<>();
/**
* set方法的入参类型
*/
private final Map<String, Class<?>> setTypes = new HashMap<>();
/**
* get方法的返回类型
*/
private final Map<String, Class<?>> getTypes = new HashMap<>();
/**
* 默认构造函数
*/
private Constructor<?> defaultConstructor;
/**
* 不区分大小写的属性集合
* key 属性名全大写, value 属性名
*/
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
相关属性都是在构造函数中通过Class对象加工获取的,基本包含了操作类的元数据。额外提供了不区分大小写的属性集合,为了属性查找、下划线转驼峰提供支持。
总结就是Class类增强,提供对property的一些简便操作方法。
ReflectorFactory
Reflector工厂,就是控制Reflector的创建,目的是为了缓存Reflector,Reflector虽好用,但是其创建过程比较重,使用了java的反射api,如果对同一class频繁创建性能会被影响,且反射元数据也不会更改,缓存其是必须的。
DefaultReflectorFactory直接使用HashMap缓存Reflector,key是Class,value是Reflector。
MetaClass
MetaClass又是Reflector的增强类,包含了Reflector和ReflectorFactory,又额外提供了对属性表达式的解析。
java">public class MetaClass {
private final ReflectorFactory reflectorFactory;
private final Reflector reflector;
}
上层应用使用MetaClass操作类,MetaClass内部使用ReflectorFactory缓存。
提供一些property相关的方法,实现委托给Reflector完成。
涉及属性表达式解析则交给PropertyTokenizer。
Wapper
wapper包,放着ObjectWapper及其实现类。对象包装器,在一个具体对象实例上添加反射功能,上面的Reflector、MetaClass都是在对静态Class各种操作,ObjectWrapper是真正有个具体的对象实例,可以执行反射操作了。
java">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);
单看提供的方法比较简单,属性动态设置/获取,属性查找、getter/setter方法操作。
BaseWrapper
提供了集合的通用方法,属性转换集合、获取/设置集合中的值。
BeanWrapper
普通Bean包装器
java">public class BeanWrapper extends BaseWrapper {
private final Object object;
private final MetaClass metaClass;
}
具体对象object、MetaClass包装,MetaClass的具象化。
借助MetaClass实现ObjectWapper定义的方法,比较简单。
java">@Override
public Object get(PropertyTokenizer prop) {
// index不为空代表是集合类型
if (prop.getIndex() != null) {
// 解析集合的值
Object collection = resolveCollection(prop, object);
return getCollectionValue(prop, collection);
} else {
return getBeanProperty(prop, object);
}
}
get和set方法都有对集合类型的处理。
MetaObject
对象元数据,对ObjectWapper的进一步增强,表达式解析反射完全支持。
最主要两个方法getValue、setValue
java">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);
}
}
java">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);
}
}
在复杂对象时可以方便的通过表达式,反射设置、获取值。
总结
反射包重点在于Reflector、MetaClass、ObjectWapper、MetaObject的设计,职责清晰一层一层加强,遵守单一原则,在我们日常业务实现设计时值得借鉴。