手敲Mybatis-反射工具天花板
Posted 渣渣洒泪成长记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手敲Mybatis-反射工具天花板相关的知识,希望对你有一定的参考价值。
历时漫长的岁月,终于鼓起勇气继续研究Mybatis的反射工具类们,简直就是把反射玩出花,但是理解起来还是很有难度的,涉及的内容代码也颇多,所以花费时间也比较浩大,不过当了解套路每个类的功能也好,设计也好,基本也可以浓缩成一句话理解,心中有了系统也好似没有那么难理解了,本节如在工作中使用到此场景,可以拿来当作工具直接使用。
前言-为什么使用反射
在手敲Mybatis-数据源池化处理实现那一节,我们留下了坑需要填,在获取连接时,数据库连接的设置还是硬编码,如果我们此时xml文件又需要新增加一些属性,就需要进行修改代码,会发现代码设计不太灵活,本节就为了解决此问题,来一起写一个很强大的反射工具类。
UML类图-类关系介绍
MyBatis设计将分为以下几个类,元类、元对象、对象包装器、反射器、调用者、对象工厂,下面就介绍这几个设计都是干什么的:
SystemMetaObject:系统入口,万物的开始,系统级别的元对象
MetaObject:元对象,外部系统调用入口,封装了包装器对象,在构造方法中使用策略模式来调用不同的对象包装器
MetaClass:元类,通过对象包装器进入,此类是对反射器的封装并进一步进行处理某些场景复杂操作
Reflector:反射器,解析对象的属性、方法、类型的解析器,最后组装起来,提供基础的方法获取数据
ObjectWrapper:对象包装器接口,定义对象基本信息
BaseWrapper:基础包装器,抽取共用包装器方法,解析集合获取集合设置集合等处理
BeanWrapper:原生包装器,对bean对象进行处理,由此方法进入MetaClass类最后进入 Reflector反射将对象数据得到。
CollectionWrapper:原生集合包装器
MapWrapper:map集合包装器,处理map对象
ObjectWrapperFactory:对象包装器工厂接口,可以获取对象包装器
DefaultObjectWrapperFactory:实现对象包装器工厂接口
ObjectFactory:对象工厂接口
DefaultObjectFactory:默认对象工厂接口,创建对象实例处理
Invoker: 调用者接口,定义反射调用
MethodInvoker:方法调用者,反射方法的
GetFieldInvoker :此类用于执行读取属性值的反射操作
SetFieldInvoker:用于执行设置属性值的反射操作
PropertyNamer:属性命名器,会将方法转换为属性名称
PropertyTokenizer :属性解析器,属性也不只有单一属性也会有复杂属性,例如属性.属性,集合等
执行流程:SystemMetaObject-->MetaObject-->ObjectWrapper-->MetaClass-->Reflector-->Invoker
而属解析器在处理中有时各个类都会用,反射器工具类要用的就这个20个类,想必你通过介绍大大致对它有印象了,可以对应看下uml图理解理解
完整代码实现
3.1 反射调用者
package df.middleware.mybatis.reflection.invoker
Invoker:反射调用者接口,定义invoke方法,子类具体实现对应的调用者,因为反射调用离不开目标对象和参数,所以此接口统一定义invoke()。
/**
* @description 调用者接口
* @date 2022/5/2
* 此接口的作用统一基于反射处理方法和属性的调用方式,采取策略模式
*/
public interface Invoker
/**
* 执行反射操作
*
* @param target 方法或者属性执行的目标对象
* @param args 方法或者属性执行时依赖的参数
*/
Object invoke(Object target, Object[] args) throws Exception;
/**
*方法或者属性对应的类型
*/
Class<?> getType();
MethodInvoker:方法调用者,构造函数会传对应的目标方method,再通过反射进行调用目标方法
/**
* @description 方法调用者
* 用于执行方法的反射操作
*/
public class MethodInvoker implements Invoker
private Class<?> type;
private Method method;
/**
* 如果方法是getter方法,则表示返回值类型
* 如果方法是setter方法,则表示入参类型
*/
public MethodInvoker(Method method)
this.method = method;
// 利用方法是否有无入参判断方法是get还是set方法,
// 如果只有一个参数,返回参数类型,否则返回 return 类型
if (method.getParameterTypes().length == 1)
// set方法获取方法入参类型赋给type属性
type = method.getParameterTypes()[0];
else
// get方法则获取方法返回类型赋给type属性
type = method.getReturnType();
@Override
public Object invoke(Object target, Object[] args) throws Exception
// 执行方法
return method.invoke(target, args);
@Override
public Class<?> getType()
return type;
GetFieldInvoker:获取属性调用者,构造函数会传目标属性Field,通过反射获取属性值并返回
/**
* @description getter 调用者
* 属性是会有set和get的,所以字段会有GetFieldInvoker和SetFieldInvoker
* 此类用于执行读取属性值的反射操作
*/
public class GetFieldInvoker implements Invoker
private Field field;
public GetFieldInvoker(Field field)
this.field = field;
@Override
public Object invoke(Object target, Object[] args) throws Exception
// 基于反射获取指定属性值
return field.get(target);
// 获取对应属性的类型
@Override
public Class<?> getType()
return field.getType();
SetFieldInvoker:设置属性调用者,构造函数会传目标属性Field,通过反射给目标属性设置值,设置是不返回的,这里就返回空
/**
* @description setter 调用者
* 用于执行设置属性值的反射操作
*/
public class SetFieldInvoker implements Invoker
private Field field;
public SetFieldInvoker(Field field)
this.field = field;
@Override
public Object invoke(Object target, Object[] args) throws Exception
// 为指定属性设置值的功能
field.set(target, args[0]);
return null;
@Override
public Class<?> getType()
return field.getType();
3.2反射器
Reflector:反射器,这个类代码相对很多,大体主要是用反射将对象信息解析出来,如类里的默认构造方法,以及属性和方法等等,解析出来处理成我们想要的数据以后存储各个容器里。这样我们数据有了,还需要添加一些对外获取容器数据的公共方法,这就是这个类的全部职责,其实也还好,就是代码多些,但是知道大致处理内容,也就没有那么难理解了,需要多debug熟悉。
/**
* 反射器,属性 get/set 的映射器
* */
public class Reflector
private static boolean classCacheEnabled = true;
private static final String[] EMPTY_STRING_ARRAY = new String[0];
// 线程安全的缓存
private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<>();
private Class<?> type;
/**
* get 属性列表,可读属性名称数组,用于保存 getter 方法对应的属性名称
* */
private String[] readablePropertyNames = EMPTY_STRING_ARRAY;
/**
* set 属性列表,可写属性名称数组,用于保存 setter 方法对应的属性名称
* */
private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;
/**
* set 方法列表,
* 用于保存属性名称到 Invoke 的映射。setter 方法会被封装到 MethodInvoker 对象中
* */
private Map<String, Invoker> setMethods = new HashMap<>();
/**
* get 方法列表
* 用于保存属性名称到 Invoke 的映射。同上,getter 方法也会被封装到 MethodInvoker 对象中
* */
private Map<String, Invoker> getMethods = new HashMap<>();
/**
* 用于保存 setter 对应的属性名与参数类型的映射
* */
private Map<String, Class<?>> setTypes = new HashMap<>();
/**
* 用于保存 getter 对应的属性名与返回值类型的映射
* */
private Map<String, Class<?>> getTypes = new HashMap<>();
// 默认构造函数
private Constructor<?> defaultConstructor;
/**
* 用于保存大写属性名与属性名之间的映射,比如 <NAME, name>
* */
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
// 解析所有的属性和方法并把数据处理到全局变量里
public Reflector(Class<?> clazz)
this.type = clazz;
// 加入构造函数
addDefaultConstructor(clazz);
// 反射解析getter方法加入 getterMethods
addGetMethods(clazz);
// 反射解析setter方法加入 setterMethods
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);
private void addDefaultConstructor(Class<?> clazz)
Constructor<?>[] consts = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : consts)
if (constructor.getParameterTypes().length == 0)
if (canAccessPrivateMethods())
try
constructor.setAccessible(true);
catch (Exception ignore)
// Ignored. This is only a final precaution, nothing we can do
if (constructor.isAccessible())
this.defaultConstructor = constructor;
private void addGetMethods(Class<?> clazz)
Map<String, List<Method>> conflictingGetters = new HashMap<>();
// 获取类中的方法
Method[] methods = getClassMethods(clazz);
for (Method method : methods)
String name = method.getName();
if (name.startsWith("get") && name.length() > 3)
if (method.getParameterTypes().length == 0)
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
else if (name.startsWith("is") && name.length() > 2)
if (method.getParameterTypes().length == 0)
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingGetters, name, method);
resolveGetterConflicts(conflictingGetters);
private void addSetMethods(Class<?> clazz)
Map<String, List<Method>> conflictingSetters = new HashMap<>();
Method[] methods = getClassMethods(clazz);
for (Method method : methods)
String name = method.getName();
if (name.startsWith("set") && name.length() > 3)
if (method.getParameterTypes().length == 1)
name = PropertyNamer.methodToProperty(name);
addMethodConflict(conflictingSetters, name, method);
resolveSetterConflicts(conflictingSetters);
private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)
for (String propName : conflictingSetters.keySet())
List<Method> setters = conflictingSetters.get(propName);
Method firstMethod = setters.get(0);
if (setters.size() == 1)
addSetMethod(propName, firstMethod);
else
Class<?> expectedType = getTypes.get(propName);
if (expectedType == null)
throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
"specification and can cause unpredicatble results.");
else
Iterator<Method> methods = setters.iterator();
Method setter = null;
while (methods.hasNext())
Method method = methods.next();
if (method.getParameterTypes().length == 1
&& expectedType.equals(method.getParameterTypes()[0]))
setter = method;
break;
if (setter == null)
throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass() + ". This breaks the JavaBeans " +
"specification and can cause unpredicatble results.");
addSetMethod(propName, setter);
// 加入set方法以MethodInvoker放入全局变量里
private void addSetMethod(String name, Method method)
if (isValidPropertyName(name))
setMethods.put(name, new MethodInvoker(method));
setTypes.put(name, method.getParameterTypes()[0]);
private void addFields(Class<?> clazz)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields)
if (canAccessPrivateMethods())
try
field.setAccessible(true);
catch (Exception e)
// Ignored. This is only a final precaution, nothing we can do.
if (field.isAccessible())
if (!setMethods.containsKey(field.getName()))
// issue #379 - removed the check for final because JDK 1.5 allows
// modification of final fields through reflection (JSR-133). (JGB)
// pr #16 - final static can only be set by the classloader
int modifiers = field.getModifiers();
if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)))
addSetField(field);
if (!getMethods.containsKey(field.getName()))
addGetField(field);
if (clazz.getSuperclass() != null)
addFields(clazz.getSuperclass());
private void addSetField(Field field)
if (isValidPropertyName(field.getName()))
setMethods.put(field.getName(), new SetFieldInvoker(field));
setTypes.put(field.getName(), field.getType());
private void addGetField(Field field)
if (isValidPropertyName(field.getName()))
getMethods.put(field.getName(), new GetFieldInvoker(field));
getTypes.put(field.getName(), field.getType());
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters)
for (String propName : conflictingGetters.keySet())
List<Method> getters = conflictingGetters.get(propName);
Iterator<Method> iterator = getters.iterator();
Method firstMethod = iterator.next();
if (getters.size() == 1)
// 存放全局变量里
addGetMethod(propName, firstMethod);
else
// 多个方法情况
Method getter = firstMethod;
Class<?> getterType = firstMethod.getReturnType();
while (iterator.hasNext())
Method method = iterator.next();
Class<?> methodType = method.getReturnType();
if (methodType.equals(getterType))
throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass()
+ ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
else if (methodType.isAssignableFrom(getterType))
// OK getter type is descendant
else if (getterType.isAssignableFrom(methodType))
getter = method;
getterType = methodType;
else
throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property "
+ propName + " in class " + firstMethod.getDeclaringClass()
+ ". This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
addGetMethod(propName, getter);
// 加入get方法以MethodInvoker放入全局变量里
private void addGetMethod(String name, Method method)
if (isValidPropertyName(name))
getMethods.put(name, new MethodInvoker(method));
getTypes.put(name, method.getReturnType());
private boolean isValidPropertyName(String name)
return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method)
List<Method> list = conflictingMethods.computeIfAbsent(name, k -> new ArrayList<>());
list.add(method);
// 查找当前类及父类方法
private Method[] getClassMethods(Class<?> cls)
Map<String, Method> uniqueMethods = new HashMap<String, Method>();
Class<?> currentClass = cls;
while (currentClass != null)
addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());
// we also need to look for interface methods -
// because the class may be abstract
Class<?>[] interfaces = currentClass.getInterfaces();
for (Class<?> anInterface : interfaces)
addUniqueMethods(uniqueMethods, anInterface.getMethods());
currentClass = currentClass.getSuperclass();
Collection<Method> methods = uniqueMethods.values();
return methods.toArray(new Method[methods.size()]);
// 校验方法唯一性,暂存临时集合
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods)
for (Method currentMethod : methods)
if (!currentMethod.isBridge())
//取得签名 方法返回值#方法名:方法参数(多个用逗号分割)
String signature = getSignature(currentMethod);
// check to see if the method is already known
// if it is known, then an extended class must have
// overridden a method
if (!uniqueMethods.containsKey(signature))
if (canAccessPrivateMethods())
try
currentMethod.setAccessible(true);
catch (Exception e)
// Ignored. This is only a final precaution, nothing we can do.
uniqueMethods.put(signature, currentMethod);
private String getSignature(Method method)
StringBuilder sb = new StringBuilder();
Class<?> returnType = method.getReturnType();
if (returnType != null)
sb.append(returnType.getName()).append('#');
sb.append(method.getName());
Class<?>[] parameters = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++)
if (i == 0)
sb.append(':');
else
sb.append(',');
sb.append(parameters[i].getName());
return sb.toString();
private static boolean canAccessPrivateMethods()
try
SecurityManager securityManager = System.getSecurityManager();
if (null != securityManager)
securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
catch (SecurityException e)
return false;
return true;
public Class<?> getType()
return type;
// -------------------------------------------解析并存储的数据需要对外提供基础容器获取---------------
public Constructor<?> getDefaultConstructor()
if (defaultConstructor != null)
return defaultConstructor;
else
throw new RuntimeException("There is no default constructor for " + type);
public boolean hasDefaultConstructor()
return defaultConstructor != null;
public Class<?> getSetterType(String propertyName)
Class<?> clazz = setTypes.get(propertyName);
if (clazz == null)
throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
return clazz;
public Invoker getGetInvoker(String propertyName)
Invoker method = getMethods.get(propertyName);
if (method == null)
throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
return method;
public Invoker getSetInvoker(String propertyName)
Invoker method = setMethods.get(propertyName);
if (method == null)
throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
return method;
/*
* Gets the type for a property getter
*
* @param propertyName - the name of the property
* @return The Class of the propery getter
*/
public Class<?> getGetterType(String propertyName)
Class<?> clazz = getTypes.get(propertyName);
if (clazz == null)
throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
return clazz;
/*
* Gets an array of the readable properties for an object
*
* @return The array
*/
public String[] getGetablePropertyNames()
return readablePropertyNames;
/*
* Gets an array of the writeable properties for an object
*
* @return The array
*/
public String[] getSetablePropertyNames()
return writeablePropertyNames;
/*
* Check to see if a class has a writeable property by name
*
* @param propertyName - the name of the property to check
* @return True if the object has a writeable property by the name
*/
public boolean hasSetter(String propertyName)
return setMethods.keySet().contains(propertyName);
/*
* Check to see if a class has a readable property by name
*
* @param propertyName - the name of the property to check
* @return True if the object has a readable property by the name
*/
public boolean hasGetter(String propertyName)
return getMethods.keySet().contains(propertyName);
public String findPropertyName(String name)
return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
/*
* Gets an instance of ClassInfo for the specified class.
* 得到某个类的反射器,是静态方法,而且要缓存,又要多线程,所以REFLECTOR_MAP是一个ConcurrentHashMap
*
* @param clazz The class for which to lookup the method cache.
* @return The method cache for the class
*/
public static Reflector forClass(Class<?> clazz)
if (classCacheEnabled)
// synchronized (clazz) removed see issue #461
// 对于每个类来说,我们假设它是不会变的,这样可以考虑将这个类的信息(构造函数,getter,setter,字段)加入缓存,以提高速度
Reflector cached = REFLECTOR_MAP.get(clazz);
if (cached == null)
cached = new Reflector(clazz);
REFLECTOR_MAP.put(clazz, cached);
return cached;
else
return new Reflector(clazz);
public static void setClassCacheEnabled(boolean classCacheEnabled)
Reflector.classCacheEnabled = classCacheEnabled;
public static boolean isClassCacheEnabled()
return classCacheEnabled;
3.3 元类
MetaClass:元类,因为反射器都是基础的操作,为了方便使用对反射器的进一步封装,获取反射器里的容器数据,元类里提供反射器缓存,这样不用相同的类每次调用都解析处理了,也是补充丰富了反射器基础的操作,相当于解构一个对象包装一个元类,而这些元类,包装器,对象工厂再组合成一个元对象,相当于说这些元类和元对象都是对我们需要操作的原对象解耦后的封装。有了这样的操作,就可以让我们处理每一个属性或者方法了。
/**
* @description 元类
* Reflector 反射器类提供的是最基础的核心功能,很多方法也都是私有的,为了更加方便的使用,
* 还需要做一层元类的包装。在元类 MetaClass 提供必要的创建反射器以及使用反射器获取
* get/set 的 Invoker 反射方法
* */
public class MetaClass
// 反射器,用于解析和存储目标类中的元信息
private Reflector reflector;
// Reflector.forClass获取当前类的反射器
private MetaClass(Class<?> type)
this.reflector = Reflector.forClass(type);
public static MetaClass forClass(Class<?> type)
return new MetaClass(type);
public static boolean isClassCacheEnabled()
return Reflector.isClassCacheEnabled();
public static void setClassCacheEnabled(boolean classCacheEnabled)
Reflector.setClassCacheEnabled(classCacheEnabled);
public MetaClass metaClassForProperty(String name)
Class<?> propType = reflector.getGetterType(name);
return MetaClass.forClass(propType);
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();
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());
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);
private MetaClass metaClassForProperty(PropertyTokenizer prop)
Class<?> propType = getGetterType(prop);
return MetaClass.forClass(propType);
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 method.getGenericReturnType();
else if (invoker instanceof GetFieldInvoker)
Field _field = GetFieldInvoker.class.getDeclaredField("field");
_field.setAccessible(true);
Field field = (Field) _field.get(invoker);
return field.getGenericType();
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();
3.4 对象包装器
ObjectWapper:对象包装器接口,定义对象基本操作,获取对象值、设置对象值、查找属性、获取get方法、获取set方法、属性类型、添加属性、设置属性等等...对象包装器主要是定义了更加明确的使用方法。
package df.middleware.mybatis.reflection.wrapper
/**
* @description 对象包装器
* 是对对象的包装的接口,抽象了对象的字段信息、 getter| setter 方法、和上面三个成员的数据类型,
* 它定义了一系列查询对象属性信息的方法,以及更新属性的方法 。添加属性方法
*/
public interface ObjectWrapper
// get
Object get(PropertyTokenizer prop);
// set
void set(PropertyTokenizer prop, Object value);
// 查找属性
String findProperty(String name, boolean useCamelCaseMapping);
// 取得getter的名字列表
String[] getGetterNames();
// 取得setter的名字列表
String[] getSetterNames();
//取得setter的类型
Class<?> getSetterType(String name);
// 取得getter的类型
Class<?> getGetterType(String name);
// 是否有指定的setter
boolean hasSetter(String name);
// 是否有指定的getter
boolean hasGetter(String name);
// 实例化属性
MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);
// 是否是集合
boolean isCollection();
// 添加属性
void add(Object element);
// 添加属性
<E> void addAll(List<E> element);
BaseWrapper:基础对象包装器,抽象类,实现ObjectWapper,主要是抽取公共代码,方便由各子类对象包装器使用,如处理集合则可调用基础对象包装器方法即可,此类主要处理解析集合、获取集合、设置集合中的值
/**
* @description 对象包装器抽象基类,提供一些工具方法
* BaseWrapper 抽象类 定义了集合的相关操作。
* 1.解析集合
* 2.获取集合中的值
* 3.设置集合中的值
* */
public abstract class BaseWrapper implements ObjectWrapper
protected static final Object[] NO_ARGUMENTS = new Object[0];
protected MetaObject metaObject;
protected BaseWrapper(MetaObject metaObject)
this.metaObject = metaObject;
/**
* 解析集合
*/
protected Object resolveCollection(PropertyTokenizer prop, Object object)
if ("".equals(prop.getName()))
return object;
else
return metaObject.getValue(prop.getName());
/**
* 取集合的值
* 中括号有2个意思,一个是Map,一个是List或数组
*/
protected Object getCollectionValue(PropertyTokenizer prop, Object collection)
if (collection instanceof Map)
//map['name']
return ((Map) collection).get(prop.getIndex());
else
int i = Integer.parseInt(prop.getIndex());
if (collection instanceof List)
//list[0]
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 RuntimeException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
/**
* 设集合的值
* 中括号有2个意思,一个是Map,一个是List或数组
*/
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 RuntimeException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
MapWrapper:Map对象包装器,是对Map对象的封装,继承了 BaseWrapper,构造传入map类型对象,获取设置值等等也以map方式即可。
/**
* @description Map 包装器
* MapWrapper 是 Map 集合对象的封装。
*/
public class MapWrapper extends BaseWrapper
// 原来的对象
private Map<String, Object> map;
public MapWrapper(MetaObject metaObject, Map<String, Object> map)
super(metaObject);
this.map = map;
// get,set是允许的,
@Override
public Object get(PropertyTokenizer prop)
//如果有index,说明是集合,那就要分解集合,调用的是BaseWrapper.resolveCollection 和 getCollectionValue
if (prop.getIndex() != null)
Object collection = resolveCollection(prop, map);
return getCollectionValue(prop, collection);
else
return map.get(prop.getName());
@Override
public void set(PropertyTokenizer prop, Object value)
if (prop.getIndex() != null)
Object collection = resolveCollection(prop, map);
setCollectionValue(prop, collection, value);
else
map.put(prop.getName(), value);
@Override
public String findProperty(String name, boolean useCamelCaseMapping)
return name;
@Override
public String[] getGetterNames()
return map.keySet().toArray(new String[map.keySet().size()]);
@Override
public String[] getSetterNames()
return map.keySet().toArray(new String[map.keySet().size()]);
@Override
public Class<?> getSetterType(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return Object.class;
else
return metaValue.getSetterType(prop.getChildren());
else
if (map.get(name) != null)
return map.get(name).getClass();
else
return Object.class;
@Override
public Class<?> getGetterType(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return Object.class;
else
return metaValue.getGetterType(prop.getChildren());
else
if (map.get(name) != null)
return map.get(name).getClass();
else
return Object.class;
@Override
public boolean hasSetter(String name)
return true;
@Override
public boolean hasGetter(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
if (map.containsKey(prop.getIndexedName()))
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return true;
else
return metaValue.hasGetter(prop.getChildren());
else
return false;
else
return map.containsKey(prop.getName());
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
HashMap<String, Object> map = new HashMap<String, Object>();
set(prop, map);
return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());
@Override
public boolean isCollection()
return false;
@Override
public void add(Object element)
throw new UnsupportedOperationException();
@Override
public <E> void addAll(List<E> element)
throw new UnsupportedOperationException();
CollectionWrapper:Collection对象包装器,实现ObjectWapper接口,除了添加集合、暂不支持其他操作,抛出异常即可。
/**
* @author 小傅哥,微信:fustack
* @description Collection 包装器
*/
public class CollectionWrapper implements ObjectWrapper
// 原来的对象
private Collection<Object> object;
public CollectionWrapper(MetaObject metaObject, Collection<Object> object)
this.object = object;
// get,set都是不允许的,只能添加元素
@Override
public Object get(PropertyTokenizer prop)
throw new UnsupportedOperationException();
@Override
public void set(PropertyTokenizer prop, Object value)
throw new UnsupportedOperationException();
@Override
public String findProperty(String name, boolean useCamelCaseMapping)
throw new UnsupportedOperationException();
@Override
public String[] getGetterNames()
throw new UnsupportedOperationException();
@Override
public String[] getSetterNames()
throw new UnsupportedOperationException();
@Override
public Class<?> getSetterType(String name)
throw new UnsupportedOperationException();
@Override
public Class<?> getGetterType(String name)
throw new UnsupportedOperationException();
@Override
public boolean hasSetter(String name)
throw new UnsupportedOperationException();
@Override
public boolean hasGetter(String name)
throw new UnsupportedOperationException();
@Override
public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory)
throw new UnsupportedOperationException();
@Override
public boolean isCollection()
return true;
@Override
public void add(Object element)
object.add(element);
@Override
public <E> void addAll(List<E> element)
object.addAll(element);
BeanWrapper:原始对象的封装,自定义对象封装,继承BaseWapper,这个是重点,因为是Bean对象,我们需要解析类里属性以及get,set方法,此时我们需要通过元类进入反射器进行解析,所以BeanWrapper依赖MetaClass
/**
* @description Bean 包装器
* BeanWrapper 是原始对象的封装
*/
public class BeanWrapper extends BaseWrapper
// 原来的对象
private Object object;
// 元类
private MetaClass metaClass;
public BeanWrapper(MetaObject metaObject, Object object)
super(metaObject);
this.object = object;
// 通过元类获取反射器 1个入口
this.metaClass = MetaClass.forClass(object.getClass());
@Override
public Object get(PropertyTokenizer prop)
// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValue
if (prop.getIndex() != null)
Object collection = resolveCollection(prop, object);
return getCollectionValue(prop, collection);
else
// 否则,getBeanProperty
return getBeanProperty(prop, object);
@Override
public void set(PropertyTokenizer prop, Object value)
// 如果有index,说明是集合,那就要解析集合,调用的是BaseWrapper.resolveCollection 和 setCollectionValue
if (prop.getIndex() != null)
Object collection = resolveCollection(prop, object);
setCollectionValue(prop, collection, value);
else
// 否则,setBeanProperty
setBeanProperty(prop, object, value);
@Override
public String findProperty(String name, boolean useCamelCaseMapping)
return metaClass.findProperty(name, useCamelCaseMapping);
@Override
public String[] getGetterNames()
return metaClass.getGetterNames();
@Override
public String[] getSetterNames()
return metaClass.getSetterNames();
@Override
public Class<?> getSetterType(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return metaClass.getSetterType(name);
else
return metaValue.getSetterType(prop.getChildren());
else
return metaClass.getSetterType(name);
@Override
public Class<?> getGetterType(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return metaClass.getGetterType(name);
else
return metaValue.getGetterType(prop.getChildren());
else
return metaClass.getGetterType(name);
@Override
public boolean hasSetter(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
if (metaClass.hasSetter(prop.getIndexedName()))
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return metaClass.hasSetter(name);
else
return metaValue.hasSetter(prop.getChildren());
else
return false;
else
return metaClass.hasSetter(name);
@Override
public boolean hasGetter(String name)
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext())
if (metaClass.hasGetter(prop.getIndexedName()))
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
return metaClass.hasGetter(name);
else
return metaValue.hasGetter(prop.getChildren());
else
return false;
else
return metaClass.hasGetter(name);
@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());
set(prop, newObject);
catch (Exception e)
throw new RuntimeException("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;
@Override
public boolean isCollection()
return false;
@Override
public void add(Object element)
throw new UnsupportedOperationException();
@Override
public <E> void addAll(List<E> list)
throw new UnsupportedOperationException();
private Object getBeanProperty(PropertyTokenizer prop, Object object)
try
// 得到getter方法,然后调用
Invoker method = metaClass.getGetInvoker(prop.getName());
return method.invoke(object, NO_ARGUMENTS);
catch (RuntimeException e)
throw e;
catch (Throwable t)
throw new RuntimeException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t);
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value)
try
// 得到setter方法,然后调用
Invoker method = metaClass.getSetInvoker(prop.getName());
Object[] params = value;
method.invoke(object, params);
catch (Throwable t)
throw new RuntimeException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);
3.5 元对象
有了元类,反射器,对象包装器,最后我们统一一个元对象进行封装,对外统一调用方式,组成一个完整的元对象操作类。通过构造方法创建不同的对象包装器,获取此类中方法则自然调度到不同的wapper包装器里,实现整条链路
/**
* @description 元对象
* */
public class MetaObject
// 原对象
private Object originalObject;
/**
* 封装过的 Object 对象
*/
// 对象包装器
private ObjectWrapper objectWrapper;
// 对象工厂
private ObjectFactory objectFactory;
// 对象包装工厂
private ObjectWrapperFactory objectWrapperFactory;
// 赋值为不同的包装器
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory)
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
if (object instanceof ObjectWrapper)
// 如果对象本身已经是ObjectWrapper型,则直接赋给objectWrapper
this.objectWrapper = (ObjectWrapper) object;
else if (objectWrapperFactory.hasWrapperFor(object))
// 如果有包装器,调用ObjectWrapperFactory.getWrapperFor
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
else if (object instanceof Map)
// 如果是Map型,返回MapWrapper
this.objectWrapper = new MapWrapper(this, (Map) object);
else if (object instanceof Collection)
// 如果是Collection型,返回CollectionWrapper
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
else
// 除此以外,返回BeanWrapper
this.objectWrapper = new BeanWrapper(this, object);
/**
* 创建 MetaObject 对象
*
* @param object 原始 Object 对象
* @param objectFactory
* @param objectWrapperFactory
* @return MetaObject 对象
*/
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory)
if (object == null)
// 处理一下null,将null包装起来
return SystemMetaObject.NULL_META_OBJECT;
else
return new MetaObject(object, objectFactory, objectWrapperFactory);
public ObjectFactory getObjectFactory()
return objectFactory;
public ObjectWrapperFactory getObjectWrapperFactory()
return objectWrapperFactory;
public Object getOriginalObject()
return originalObject;
/* --------以下方法都是委派给 ObjectWrapper------ */
// 查找属性,相当于又封装了一层
public String findProperty(String propName, boolean useCamelCaseMapping)
return objectWrapper.findProperty(propName, useCamelCaseMapping);
/**
* 获取get方法属性名称和get方法去掉get后边的属性名称
* getIds()return id; --> (id、ids)
* @return
*/
// 取得getter的名字列表
public String[] getGetterNames()
return objectWrapper.getGetterNames();
/**
* 获取set方法属性名称和set方法去掉set后边的属性名称
* setIds()return id; --> (id、ids)
* @return
*/
// 取得setter的名字列表
public String[] getSetterNames()
return objectWrapper.getSetterNames();
/**
* 获取set方法后边属性的类型
* @param name 这个name 要和setXXX方法中的XXX相同才能获取到,否则抛异常
* @return
*/
// 取得setter的类型列表
public Class<?> getSetterType(String name)
return objectWrapper.getSetterType(name);
/**
* 获取get方法后边属性的类型
* @param name 这个name,要个getXXX方法中的XXX相同才能获取到,否则抛异常
* @return
*/
// 取得getter的类型列表
public Class<?> getGetterType(String name)
return objectWrapper.getGetterType(name);
/**
* 判断name是否是setXXX()方法中的XXX
* @param name
* @return
*/
//是否有指定的setter
public boolean hasSetter(String name)
return objectWrapper.hasSetter(name);
/**
* 判断name是否是getXXX()方法中的XXX
* @param name
* @return
*/
// 是否有指定的getter
public boolean hasGetter(String name)
return objectWrapper.hasGetter(name);
/**
* 获取对象属性值,可以递归获取
* @param name
* @return
*/
// 取得值
// 如 班级[0].学生.成绩
public Object getValue(String name)
// 创建 PropertyTokenizer 对象,对 name 分词
PropertyTokenizer prop = new PropertyTokenizer(name);
// 有子表达式
if (prop.hasNext())
// 创建 MetaObject 对象,递归调用
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
// 递归判断子表达式 children ,获取值,metaValue == null,则返回null
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
// 如果上层就是null了,那就结束,返回null
return null;
else
// 否则继续看下一层,递归调用getValue
return metaValue.getValue(prop.getChildren());
else
// 无子表达式,取值
return objectWrapper.get(prop);
/**
* 给对象属性设置值,可以递归设置,基本类型,数组,对象,都可以自动创建
* 但是ArrayList和数组需要手动创建
* List必须创建对象,添加进list
* @param name
* @param value
*/
// 如 班级[0].学生.成绩
public void setValue(String name, Object value)
// 创建 PropertyTokenizer 对象,对 name 分词
PropertyTokenizer prop = new PropertyTokenizer(name);
// 有子表达式
if (prop.hasNext())
// 创建 MetaObject 对象
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
// 递归判断子表达式 children ,设置值
if (metaValue == SystemMetaObject.NULL_META_OBJECT)
if (value == null && prop.getChildren() != null)
// don't instantiate child path if value is null
// 如果上层就是 null 了,还得看有没有儿子,没有那就结束
return;
else
// 创建值
// 否则还得 new 一个,委派给 ObjectWrapper.instantiatePropertyValue
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
// 递归调用setValue
metaValue.setValue(prop.getChildren(), 以上是关于手敲Mybatis-反射工具天花板的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis 源码学习-反射工具(Property 工具)
Mybatis 源码学习-反射工具(TypeParameterResolver)