mybatis源码分析之反射包分析
mybatis解析xml时完成参数对象或者结果集对象等初始化,在执行流程中又要去动态修改这些对象的属性,所以单独设计了一套反射工具包,这些类封装在reflection包中,mybatis处理SQL参数或者结果集的时候几乎都有反射包的身影,这些主要类之间的依赖关系如下:
以SystemMetaObject.forObject(Object object)为入口,获取到MetaObject,以后目标对象的get、set方法都在MetaObject中执行了。
以正常的javabean对象为例子分析,执行MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);方法判断object对象,是集合类型还是Javabean类型,如果是Javabean类型,就实例化BeanWrapper等对象,主要类之间的依赖关系如图所示,大概描述下这几个类的作用:
MetaObject:根据目标对象类型,实例化不同的ObjectWrapper,还可以处理如XX.xx传入这种属性名的处理,以后调用get、set方法都用这个类,XX.xx属性内部代码实现:
public void setValue(String name, Object value) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
//处理XX.xx属性,先判断XX是什么类型的ObjectWrapper,如果是对象就返回SystemMetaObject.NULL_META_OBJECT,Map返回MapWrapper,List返回ObjectWrapper
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
return;
} else {
//XX类的set方法设置,并返回这个类的MetaValue(用于子属性的设置set方法设置)
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
}
}
metaValue.setValue(prop.getChildren(), value);
} else {
objectWrapper.set(prop, value);
}
}
BeanWrapper:符合Javabean规范对象的封装类,通过MetaClass获取到Invoker对象,再调用method.invoke()方法执行原对象的内部方法.
PropertyTokenizer:属性分割解析器,可以处理多种参数写法,如:richType.richField、richMap.key、richMap[key](Map类型属性)、richType.richMap[key]、richList[0](List类型属性)、richType.richList[0]
DefaultObjectFactory:通过反射实例化类,可以修改构造函数的访问权限
MetaClass:通过传入目标对象的Class对象,Reflector对属性进行一些操作封装
Reflector:真正对接JDK接口实现反射的工具类,目标对象初始化时就把所有的get,set方法装进map,如果属性没有get\set方法,反射原理设置get/set方法,并把方法保存到map中,具体代码实现:
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());
}
}
初始化时,先修改field的访问权限,field.setAccessible(true);即使是private也可以动态修改。所以结果集中的属性即使没有get/set方法,也可以赋值和取值。
GetFieldInvoker、SetFieldInvoker分别动态设置属性的get、set方法
MethodInvoker执行目标函数的方法