這篇我準備介紹下mybatis另一個基礎支撐組件,反射組件組。
1、Reflector
我們來看下Reflector類的屬性和構造器,通過屬性和構造器我們基本上就能瞭解Reflector這個類了
public class Reflector {
private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writeablePropertyNames;
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[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
}
首先我們要知道,一個類對象創建一個對應的Reflector,這個Reflector可以操作類,及這個類創建的對象
我們來解釋一下上面的屬性
type:類對象對應的Class類型
readablePropertyNames: 類對象對應的可讀屬性集合
writeablePropertyNames:類對象對應的可寫屬性集合
setMethods:類對象的set方法集合
getMethods:類對象的get方法集合
setType:類對象的set類型集合
getType:類對象的get類型集合
defaultConstructor:類對象的默認構造器
caseInsensitivePropertyMap: 記錄了所有屬性集合
我們再來看下Reflector的構造器
構造器就是獲取類對象的默認構造器、get方法集合、set方法集合,可讀屬性集合、可寫屬性集合
我們用一個示例來看看這個一個類對象被這個對象構造後的結果:
public class SysUser {
private String name;
private Integer age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
public static void main(String[] args) {
Reflector reflector = new Reflector(SysUser.class);
}
上面代碼構造了SysUser的Reflector之後,Reflector的每個屬性對應如下
type: SysUser.class
readablePropertyNames:["sex", "name", "age"]
writeablePropertyNames:["sex", "name", "age"]
setMethods:[{sex, SetFieldInvoker}, {name, MethodInvoker}, {age, MethodInvoker}]
getMethod:[{sex, GetFieldInvoker}, {name, MethodInvoker}, {age, MethodInvoker}]
setTypes:[{sex, String}, {name, String}, {age, Integer}]
getTypes:[{sex, String}, {name, String}, {age, Integer}]
defaultConstructor: SysUser的默認構造器
ReflectorFactory
public interface ReflectorFactory {
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean classCacheEnabled);
Reflector findForClass(Class<?> type);
}
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) {
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
上面代碼是ReflectorFactory的接口和默認實現:
其主要就是提供創建Reflector及緩存Reflector的功能
PropertyTokenizer
針對user.order[0].orderId這種複雜的表達式,mybatis提供了一個PropertyTokenizer解析,我們來看下PropertyTokenizer的結構
propertyTokenizer是一個迭代器。
我們在看看其實現
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
private String name;
private final String indexedName;
private String index;
private final String children;
// 找到第一個.讀出【】之間的index,最終生成一個名稱一個索引,例如order[0],name=order,index=0
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);
}
}
改組件功能就是解析屬性,找到第一個.讀出【】之間的index,最終生成一個名稱一個索引。
例如order[0],name=order,index=0
我們可以來解析一段字符串,來看看PropertyTokenizer的用法
public class PropertyTokenizerDemo {
public static void main(String[] args) {
String prop = "user.order[0].item[0].name";
parseProperty(prop);
}
public static void parseProperty(String prop){
PropertyTokenizer pt = new PropertyTokenizer(prop);
if (pt.hasNext()) {
System.out.println(pt.getName()+" "+pt.getIndex());
parseProperty(pt.getChildren());
}
}
// 輸出結果
user null
order 0
item 0
}
可見其用法和list的iterator差不多
MetaClass
通過Reflector和PropertyTokenizer,實現對複雜屬性表達式的解析。
public class MetaClass {
private final ReflectorFactory reflectorFactory;
private final Reflector reflector;
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
return new MetaClass(type, reflectorFactory);
}
public MetaClass metaClassForProperty(String name) {
Class<?> propType = reflector.getGetterType(name);
return MetaClass.forClass(propType, reflectorFactory);
}
// 獲取屬性
public String findProperty(String name) {
StringBuilder prop = buildProperty(name, new StringBuilder());
return prop.length() > 0 ? prop.toString() : null;
}
public String findProperty(String name, boolean useCamelCaseMapping) {
if (useCamelCaseMapping) {
name = name.replace("_", "");
}
return findProperty(name);
}
// 獲取所有可讀屬性
public String[] getGetterNames() {
return reflector.getGetablePropertyNames();
}
// 獲取所有可寫屬性
public String[] getSetterNames() {
return reflector.getSetablePropertyNames();
}
// 獲取name名稱對應屬性類型
public Class<?> getSetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaClass metaProp = metaClassForProperty(prop.getName());
return metaProp.getSetterType(prop.getChildren());
} else {
return reflector.getSetterType(prop.getName());
}
}
// 獲取name名稱對應屬性類型
public Class<?> getGetterType(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
MetaClass metaProp = metaClassForProperty(prop);
return metaProp.getGetterType(prop.getChildren());
}
// issue #506. Resolve the type inside a Collection Object
return getGetterType(prop);
}
// 根據PropertyTokenizer創建MetaClass
private MetaClass metaClassForProperty(PropertyTokenizer prop) {
Class<?> propType = getGetterType(prop);
return MetaClass.forClass(propType, reflectorFactory);
}
private Class<?> getGetterType(PropertyTokenizer prop) {
Class<?> type = reflector.getGetterType(prop.getName());
if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
Type returnType = getGenericGetterType(prop.getName());
if (returnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
if (actualTypeArguments != null && actualTypeArguments.length == 1) {
returnType = actualTypeArguments[0];
if (returnType instanceof Class) {
type = (Class<?>) returnType;
} else if (returnType instanceof ParameterizedType) {
type = (Class<?>) ((ParameterizedType) returnType).getRawType();
}
}
}
}
return type;
}
private Type getGenericGetterType(String propertyName) {
try {
Invoker invoker = reflector.getGetInvoker(propertyName);
if (invoker instanceof MethodInvoker) {
Field _method = MethodInvoker.class.getDeclaredField("method");
_method.setAccessible(true);
Method method = (Method) _method.get(invoker);
return TypeParameterResolver.resolveReturnType(method, reflector.getType());
} else if (invoker instanceof GetFieldInvoker) {
Field _field = GetFieldInvoker.class.getDeclaredField("field");
_field.setAccessible(true);
Field field = (Field) _field.get(invoker);
return TypeParameterResolver.resolveFieldType(field, reflector.getType());
}
} catch (NoSuchFieldException | IllegalAccessException ignored) {
}
return null;
}
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (reflector.hasSetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop.getName());
return metaProp.hasSetter(prop.getChildren());
} else {
return false;
}
} else {
return reflector.hasSetter(prop.getName());
}
}
public boolean hasGetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (reflector.hasGetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop);
return metaProp.hasGetter(prop.getChildren());
} else {
return false;
}
} else {
return reflector.hasGetter(prop.getName());
}
}
public Invoker getGetInvoker(String name) {
return reflector.getGetInvoker(name);
}
public Invoker getSetInvoker(String name) {
return reflector.getSetInvoker(name);
}
// 構造屬性
private StringBuilder buildProperty(String name, StringBuilder builder) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
String propertyName = reflector.findPropertyName(prop.getName());
if (propertyName != null) {
builder.append(propertyName);
builder.append(".");
MetaClass metaProp = metaClassForProperty(propertyName);
metaProp.buildProperty(prop.getChildren(), builder);
}
} else {
String propertyName = reflector.findPropertyName(name);
if (propertyName != null) {
builder.append(propertyName);
}
}
return builder;
}
// 是否有默認方法
public boolean hasDefaultConstructor() {
return reflector.hasDefaultConstructor();
}
}
我們通過一個複雜的屬性,並創建其MetaClass的示例來了解MetaClass
額,這個例子簡單化有點搞不定,搞定了也是類似於這個一樣複雜,分析一個例子流程圖吧:
類實例如下
public class SysUser {
private String name;
private Integer age;
private Order order;
private String sex;
}
public class Order {
private String orderId;
private Prod prod;
}
public class Prod {
private String name;
private Double price;
}
以獲取SysUser的order.prod爲例
sysUserMetaObject.getValue("order.prod")
1) PropertyTokenizer prop = new PropertyTokenizer("order.prod"); prod.hasNext()爲true
2) metaObjectForProperty(”order"),這裏面是一個遞歸調用
a) 這裏getValue("order"), 再次回到了第一步new PropertyTokenizer("order"), prod.hasNext()爲false
b) objectWrapper.get(“order”);
aa) getBeanProperty() 獲取getInvoker, 調用invoker,獲取該對象對應的屬性值,這裏是order對象
bb) 返回了一個Order對象
c) MetaObject.forObject創建一個Order對象的MetaObject
3)如果是空,返回空,否則調用order對象的MetaObject的getValue(),即orderMetaObject.getValue("prod")
以此類推最後返回一個prod對象
這兩個類之間關係確實比較複雜,類內部方法遞歸,類之間方法遞歸