1.ORM框架查询数据过程
其中实例化目标对象和对象属性赋值需要反射生成。JDBC原生的反射不好用,所以mybatis对其进行了封装。
2.反射的核心类
2.1 用于实例化目标对象的类
- ObjectFactory:MyBatis每次创建结果对象的新实例时,使用ObjectFactory构建POJO
DefaultObjectFactory的create方法:
@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
}
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
//判断类是不是集合类,如果是集合类指定具体的实现类
Class<?> classToCreate = resolveInterface(type);
// we know types are assignable
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
}
private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> constructor;
//通过无参构造函数创建对象
if (constructorArgTypes == null || constructorArgs == null) {
constructor = type.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
}
//根据指定的参数列表查找构造函数,并实例化对象
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (Exception e) {
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
for (Class<?> argType : constructorArgTypes) {
argTypes.append(argType.getSimpleName());
argTypes.append(",");
}
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
}
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty()) {
for (Object argValue : constructorArgs) {
argValues.append(String.valueOf(argValue));
argValues.append(",");
}
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
}
throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
}
}
2.2 用于对象属性赋值的类
- ReflectorFactory:创建Reflector的工厂类,Reflector是MyBatis反射模块的基础,每个Reflector对象都对应一个类,在其中缓存了反射操作所需要的类元信息
DefaultReflectorFactory类:
public class DefaultReflectorFactory implements ReflectorFactory {
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
// synchronized (type) removed see issue #461
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
Reflector类:
public class Reflector {
private final Class<?> type;//对应的class
private final String[] readablePropertyNames;//可读属性的名称集合,存在get方法即可读
private final String[] writeablePropertyNames;//可写属性的名称集合,存在set方法即可写
private final Map<String, Invoker> setMethods = new HashMap<>();//保存属性相关的set方法
private final Map<String, Invoker> getMethods = new HashMap<>();//保存属性相关的get方法
private final Map<String, Class<?>> setTypes = new HashMap<>();//保存属性相关的set方法入参类型
private final Map<String, Class<?>> getTypes = new HashMap<>();//保存属性相关的get方法返回类型
private Constructor<?> defaultConstructor;//class默认的构造函数
//记录所有属性的名称集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz);//获取clazz的默认构造函数
addGetMethods(clazz);//处理clazz中的get方法信息,填充getMethods、getTypes
addSetMethods(clazz);//处理clazz中的set方法信息,填充setMethods、setTypes
addFields(clazz);//处理没有get、set方法的属性
//根据get、set方法初始化可读属性集合和可写属性集合
readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
//初始化caseInsensitivePropertyMap
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writeablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
}
- ObjectWrapper:对对象的包装,抽象了对象的属性信息,定义了一系列查询对象属性信息的方法,以及更新属性的方法
-
ObjectWrapperFactory:ObjectWrapper的工厂类,用于创建ObjectWrapper
BeanWrapper类:
其中的相关设置属性的方法都是从MetaClass获得的。
public class BeanWrapper extends BaseWrapper {
private final Object object;
private final MetaClass metaClass;
@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);
}
}
测试代码:
@Test
public void reflectionTest(){
//反射工具类初始化
ObjectFactory objectFactory = new DefaultObjectFactory();
TUser user = objectFactory.create(TUser.class);
ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);
//使用Reflector读取类元信息
Reflector findForClass = reflectorFactory.findForClass(TUser.class);
Constructor<?> defaultConstructor = findForClass.getDefaultConstructor();
String[] getablePropertyNames = findForClass.getGetablePropertyNames();
String[] setablePropertyNames = findForClass.getSetablePropertyNames();
System.out.println(defaultConstructor.getName());
System.out.println(Arrays.toString(getablePropertyNames));
System.out.println(Arrays.toString(setablePropertyNames));
//使用ObjectWrapper读取对象信息,并对对象属性进行赋值操作
TUser userTemp = new TUser();
ObjectWrapper wrapperForUser = new BeanWrapper(metaObject, userTemp);
String[] getterNames = wrapperForUser.getGetterNames();
String[] setterNames = wrapperForUser.getSetterNames();
System.out.println(Arrays.toString(getterNames));
System.out.println(Arrays.toString(setterNames));
PropertyTokenizer prop = new PropertyTokenizer("userName");
wrapperForUser.set(prop, "lison");
System.out.println(userTemp);
结果:
com.enjoylearning.mybatis.entity.TUser
[note, realName, healthReports, jobs, sex, roles, mobile, id, position, userName, email]
[realName, note, healthReports, sex, jobs, roles, mobile, id, position, userName, email]
[note, realName, healthReports, jobs, sex, roles, mobile, id, position, userName, email]
[realName, note, healthReports, sex, jobs, roles, mobile, id, position, userName, email]
TUser [id=null, userName=lison, realName=null, sex=null, mobile=null, email=null, note=null, positionId=]
2.3 MetaObject
MetaObject封装了对象元信息,包装了MyBatis中的五个核心的反射类,也是提供给外部使用的反射工具类,可以利用它读取或者修改对象的属性信息。
测试代码:
@Test
public void reflectionTest(){
//反射工具类初始化
ObjectFactory objectFactory = new DefaultObjectFactory();
TUser user = objectFactory.create(TUser.class);
ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);
//模拟数据库行数据转化成对象
//1.模拟从数据库读取数据
Map<String, Object> dbResult = new HashMap<>();
dbResult.put("id", 1);
dbResult.put("user_name", "lison");
dbResult.put("real_name", "李晓宇");
TPosition tp = new TPosition();
tp.setId(1);
dbResult.put("position_id", tp);
//2.模拟映射关系
Map<String, String> mapper = new HashMap<String, String>();
mapper.put("id", "id");
mapper.put("userName", "user_name");
mapper.put("realName", "real_name");
mapper.put("position", "position_id");
//3.使用反射工具类将行数据转换成pojo
BeanWrapper objectWrapper = (BeanWrapper) metaObject.getObjectWrapper();
Set<Map.Entry<String, String>> entrySet = mapper.entrySet();
for (Map.Entry<String, String> colInfo : entrySet) {
String propName = colInfo.getKey();
Object propValue = dbResult.get(colInfo.getValue());
PropertyTokenizer proTokenizer = new PropertyTokenizer(propName);
objectWrapper.set(proTokenizer, propValue);
}
System.out.println(metaObject.getOriginalObject());
}
测试结果:
TUser [id=1, userName=lison, realName=李晓宇, sex=null, mobile=null, email=null, note=null, positionId=1]
参考
- 1)享学课堂Lison老师笔记