Mybatis反射模块
Mybatis中的反射模块是在Statement执行之后对结果集进行处理,转换为我们的Dao实体的重要基础模块,该模块是基于Java的高级特性-反射功能实现,并且根据Java反射又进行了进一步的封装,便于我们更加高效快捷的调用Java的反射功能对Class类和类实例进行操作。当前的Mybatis版本基于3.3.0
模块结构
│ ExceptionUtil.java
│ MetaClass.java 核心
│ MetaObject.java 核心
│ ReflectionException.java
│ Reflector.java 全局核心
│ SystemMetaObject.java
│
├─factory 对象工厂
│ DefaultObjectFactory.java
│ ObjectFactory.java
│
├─invoker 方法(setter)调用
│ GetFieldInvoker.java
│ Invoker.java
│ MethodInvoker.java
│ SetFieldInvoker.java
│
├─property 属性解析
│ PropertyCopier.java
│ PropertyNamer.java
│ PropertyTokenizer.java
│
└─wrapper 各种包装器
BaseWrapper.java
BeanWrapper.java
CollectionWrapper.java
DefaultObjectWrapperFactory.java
MapWrapper.java
ObjectWrapper.java
ObjectWrapperFactory.java
核心类总结
Reflector
⚠️ 如果要更好的理解该类的作用,必须要理解,对于Java虚拟机,即一个Java应用,Class实例在整个Java应用是唯一的,相应的,Class实例下的Method实例,Field实例也是唯一
该类是整个Mybatis反射模块的核心类,该类的主要作用是封装Mybatis用到的相关类的类型信息,即__Class__ 对象信息。
该类在Mybatis中作为全局核心,其中维护了一个静态的__ConcurrentHashMap__实例,其key值为Class对象,而键则为Reflector对象,所以在这里我们把Reflector类就当作是Class类,只不过对于Mybatisy来说,使用Reflector完全是根据自身需求又对Class对象进行又一次的__轻量__的封装,接下来让我们看看该类的核心属性和核心方法
核心属性
// 是否开启Class缓存,默认为开启
// 如果开启了,Class与Reflector将会全局缓存到 REFLECTOR_MAP中
private static boolean classCacheEnabled = true;
private static final String[] EMPTY_STRING_ARRAY = new String[0];
//Class与Refletor的缓存map,这里用ConcurrentHashMap,多线程支持,作为一个缓存
private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<Class<?>, Reflector>();
//Class类型实例
private Class<?> type;
//getter的属性列表
private String[] readablePropertyNames = EMPTY_STRING_ARRAY;
//setter的属性列表
private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;
//setter的方法列表
private Map<String, Invoker> setMethods = new HashMap<String, Invoker>();
//getter的方法列表
private Map<String, Invoker> getMethods = new HashMap<String, Invoker>();
//setter的类型列表
private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();
//getter的类型列表
private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();
//构造函数,这里是使用默认的无参构造
private Constructor<?> defaultConstructor;
private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>();
核心方法
- 构造方法
// 构造方法私有,目的是限制要使用该类生成实例,则必须传入Class对象
// 传入Class实例后,会将该Class实例的默认构造方法、getter方法、setter方法、字段解析并放入到上面对应的Map容器中
private Reflector(Class<?> clazz) {
type = clazz;
//加入构造函数
addDefaultConstructor(clazz);
//加入getter
addGetMethods(clazz);
//加入setter
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) {
//这里为了能找到某一个属性,就把他变成大写作为map的key
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
- 实例化方法
/*
* 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) {
//先查看是否开启了类型缓存,开启了就通过Class对象去获取实例
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);
}
}
- 获取Getter方法和Setter方法
🗒 获取getter方法和setter方法的原理其实很简单,就是把属性名称当作key值,把getter、setter方法当作属性分别放到Reflection类的核心属性 getMethods 和 setMethods 这两个map中
// 通过属性名称获取对应的setter方法
public Invoker getSetInvoker(String propertyName) {
Invoker method = setMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no setter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}
//通过属性名称获取对应的getter方法
public Invoker getGetInvoker(String propertyName) {
Invoker method = getMethods.get(propertyName);
if (method == null) {
throw new ReflectionException("There is no getter for property named '" + propertyName + "' in '" + type + "'");
}
return method;
}
- 核心私有方法
//将Class实例中的getter方法放入 getMethods这个Map容器中
// 同样有个addSetMethods方法 会将seter方法放入 setMethods这个Map容器中
private void addGetMethods(Class<?> cls) {
Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
//这里getter和setter都调用了getClassMethods,有点浪费效率了。不妨把addGetMethods,addSetMethods合并 成一个方法叫addMethods
Method[] methods = getClassMethods(cls);
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);
}
Invoker
Invoker类是位于mybatis反射模块下的invoker包中,是一个顶级接口,该接口的作用是对Method实例__invoke__方法的调用,即对Method方法的再次封装,目的是便于Mybatis调用setter方法
- Invoker接口
public interface Invoker {
//调用Method的invoke方法,具体由实现类决定
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
//获取类型,类型可能是方法的返回值类型,也可能是参数类型,由实现类决定
Class<?> getType();
//获取对应的Method实例,默认返回Null
default Method getMethod(){ return null; }
}
- MethodInvoker
public class MethodInvoker implements Invoker {
private Class<?> type;
private Method method;
public MethodInvoker(Method method) {
this.method = method;
//如果只有一个参数,返回参数类型,否则返回return的类型
if (method.getParameterTypes().length == 1) {
type = method.getParameterTypes()[0];
} else {
type = method.getReturnType();
}
}
//就是调用Method.invoke
@Override
public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
return method.invoke(target, args);
}
@Override
public Class<?> getType() {
return type;
}
public Method getMethod() {
return this.method;
}
}
MetaClass
MetaClass在mybatis模块中的职责是对Reflector实例进行调用,其核心属性就只有一个私有的Reflector实例,该实例不对外使用,MetaClass的所有核心方法都是基于Reflector实例中的方法进行操作
PropertyTokenizer
PropertyTokenizer是一个将属性字符串分解为标记的属性分解器
如person[0].birthdate.year,将依次取得person[0], birthdate, year
核心属性
/**
* @author Clinton Begin
*/
/**
* 属性分解为标记,迭代子模式
* 如person[0].birthdate.year,将依次取得person[0], birthdate, year
*
*/
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {
//例子: person[0].birthdate.year
private String name; //person
private String indexedName; //person[0]
private String index; //0
private String children; //birthdate.year
//此处省略了很多代码
}
核心方法
// 在构造方法分解属性,并赋值给核心属性
public PropertyTokenizer(String fullname) {
//person[0].birthdate.year
//先找到 "." 的下标
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) {
//去除中括号中的值[0],即取 “0”
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
//重写Iterator的 hasNext()方法,判断是否有子属性
//子属性的分解由构造方法实现
@Override
public boolean hasNext() {
return children != null;
}
// 重写Iterator的 next()方法,再次生成构造出一个属性解析器,并且由构造方法实现解析
@Override
public PropertyTokenizer next() {
return new PropertyTokenizer(children);
}
ObjectWrapper
ObjectWrapper,根据名字我们知道这个类是对象包装者,即对对象进行装饰的类,mybatis中对数据库实体填充数据时需要调用setter方法,就是由该类提供支持
ObjectWrapper接口
ObjectWrapper接口定义了包装类所必须的方法,但在这里mybatis将查询返回的对象类型分为Bean类型、Collection类型,Map类型。所以该接口的实现类分别有BeanWrapper,用于对普通Java进行包装;MapWrapper,对Map类型进行包装,CollectionWrapper,对List类型的数据进行包装
/**
* @author Clinton Begin
*/
/**
* 对象包装器
*
*/
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();
//添加属性
public void add(Object element);
//添加属性
public <E> void addAll(List<E> element);
}
BeanWrapper
BeanWrapper,是对JavaBean进行包装的包装器类型,通过维护一个Object类型的JavaBean对象,和一个MetaClass实例,其原理是通过调用MetaClass实例为Object类型的JavaBean设置属性和进行一些其他操作
核心属性
public class BeanWrapper extends BaseWrapper {
private static Logger logger = LoggerFactory.getLogger(BeanWrapper.class);
//原来的对象 该对象其实是一个JavaBean,只不过这里为了更新抽象,使用了Object类型来接收JavaBean
private Object object;
//元类
private MetaClass metaClass;
//此处省略了很多代码....
}
核心方法
// 执行setter方法
private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
try {
//得到setter方法,然后调用
Invoker method = metaClass.getSetInvoker(prop.getName());
logger.info("获取到setter方法:{} -- 设置值:{}",method.getMethod().getName(),value);
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);
}
}
// 执行getter方法
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
try {
//得到getter方法,然后调用
logger.info("");
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("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t);
}
}
MetaObject
MetaObject是mybatis反射模块中给对象设置属性值,调用setter方法的实际操作者,我们可以将该类比作一位指挥家,他是一个乐团的操控者,他会根据乐谱(类)指挥演奏者(ObjectWrapper、ObjectFactory、ObjectWrapperFactory)完成一首曲子(Object)
核心属性
/**
* @author Clinton Begin
*/
/**
* 元对象,各种get,set方法有点ognl表达式的味道
* 可以参考MetaObjectTest来跟踪调试,基本上用到了reflection包下所有的类
*
*/
public class MetaObject {
private static Logger logger = LoggerFactory.getLogger(MetaObject.class);
//需要设置属性的对象,在Mybatis中可以理解为数据库实体
private Object originalObject;
//对象包装器
private ObjectWrapper objectWrapper;
//对象工厂
private ObjectFactory objectFactory;
// 对象包装器工厂
private ObjectWrapperFactory objectWrapperFactory;
//此处省略了很多代码.....
}
核心方法
//私有化构造方法
// 构造方法中判断需要设置的对象是属于普通类型、Map类型、Collection类型,将ObjectWrapper进行赋值
// 不同类型的ObjectWrapper赋值时所调用方法不同
// 普通类型 调用setter方法
// Map类型 调用put方法
// Collection类型 调用add方法
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);
}
}
// 静态实例化方法
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
if (object == null) {
//处理一下null,将null包装起来
//把空值当作一个实例,当判断一个属性是否为空时,则判断生成的MetaObject是否为 //SystemMetaObject.NULL_META_OBJECT即可,并且该实例全局唯一并且使用缓存在内存中
// 使用方法类似于 Collections.emptyList() Collections.emptySet().....
return SystemMetaObject.NULL_META_OBJECT;
} else {
return new MetaObject(object, objectFactory, objectWrapperFactory);
}
}
//对象的值获取,其实内部调用getter方法
//调用顺序 ObjectWrapper.get() -- MetaClass.getGetInvoker() -- Invoker.invoke()
// 这个方法的神奇之处在于,可以通过object.field.field...的方法调用,具体逻辑有下面的两种形式
public Object getValue(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
// 如果name是object.field.field...形式的,则会递归调用,直至找到最后一个.后面的属性名称
// 具体请查看PropertyTokenizer
if (prop.hasNext()) {
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
//如果上层就是null了,那就结束,返回null
return null;
} else {
//否则继续看下一层,递归调用getValue
return metaValue.getValue(prop.getChildren());
}
} else {
// name直接是属性名称,则直接调用该属性对应的getter方法
return objectWrapper.get(prop);
}
}
// 执行逻辑与getValue方法类似
// 调用顺序 ObjectWrapper.set() -- MetaClass.getSetInvoker() -- Invoker.invoke()
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 && 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(), value);
} else {
//到了最后一层了,所以委派给ObjectWrapper.set
objectWrapper.set(prop, value);
}
}
MetaObject小结
通过阅读MetaObject的核心属性和核心方法我们可以得出一个结论,MetaObject是对JavaBean属性操作的最终执行者,他可以通过ObjectWrapper获取Getter、Setter方法,然后结合 originalObject(即我们需要操作的JavaBean),进行操作,所以MetaObject是一个非常强力的类,并且在setValue、getValue中结合PropertyTokizer类可以实现类似于__ognr__表达式的形式对属性进行更加方便、灵活的操作,MetaObject就是一个集大成者
实例
给一个JavaBean赋值
//对象工厂和对象包装器工厂
public static ObjectFactory objectFactory = new DefaultObjectFactory();
public static ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
//创建JavaBean
Role role = objectFactory.create(Role.class);
//创建元对象
MetaObject metaObject = MetaObject.forObject(role, objectFactory, objectWrapperFactory);
//赋值
metaObject.setValue("roleName","admin");