在mybatis中,ResultSetHandler在收集JDBC返回的结果后需要转换成对应的Bean对象,其实映射的原理基本大家都能想到使用的时候java中的反射机制,但是在Mybatis中,提供了一个更加强大的对象,就是MetaObject,使用这个对象不仅对Bean中的属性赋值、取值都十分简单,同时还能对嵌套对象进行操作。
1、MetaObject
MetaObject 可以操作嵌套属性。
public class MetaObject {
private final Object originalObject;
private final ObjectWrapper objectWrapper;
private final ObjectFactory objectFactory;
private final ObjectWrapperFactory objectWrapperFactory;
private final ReflectorFactory reflectorFactory;
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
ReflectorFactory reflectorFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) {
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else {
this.objectWrapper = new BeanWrapper(this, object);
}
}
}
public static void main(String[] args) {
MetaObjectBean bean = new MetaObjectBean();
Configuration configuration = new Configuration();
MetaObject metaObject = configuration.newMetaObject(bean);
metaObject.setValue("username","李逵");
metaObject.setValue("bean.address","山东");
System.out.println(bean.getBean().getAddress());//山东
List<MetaObjectChildBean> beanList = new ArrayList<>();
beanList.add(bean.getBean());
metaObject.setValue("beanList",beanList);
System.out.println(((MetaObjectChildBean)metaObject.getValue("beanList[0]")).getAddress());//山东
}
1.1、ObjectWrapper
1.1.1、BeanWrapper
BeanWapper 只能操本类的属性。
public class BeanWrapper extends BaseWrapper {
private final Object object;
private final MetaClass metaClass;
public BeanWrapper(MetaObject metaObject, Object object) {
super(metaObject);
this.object = object;
this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
}
}
1.2、ObjectFactory
public class DefaultObjectFactory implements ObjectFactory, Serializable {
private static final long serialVersionUID = -8855120656740914948L;
@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();
return constructor.newInstance();
}
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
return constructor.newInstance(constructorArgs.toArray(new Object[0]));
}
}
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class || type == Collection.class || type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) { // issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
}
1.3、ObjectWrapperFactory
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
@Override
public boolean hasWrapperFor(Object object) {
return false;
}
@Override
public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
throw new ReflectionException("The DefaultObjectWrapperFactory should never be called to provide an
ObjectWrapper.");
}
}
1.4、ReflectorFactory
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) {
// synchronized (type) removed see issue #461
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
2、MetaClass
可以操作嵌套的set、get方法.
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
2.1、属性分词器之PropertyTokenizer
当需要集合中某个元素的某个属性的时候,表达式需要这样写:list[0].user.name,这个时候就需要一个比较重要的组件去判断是否直接获取属性,还是递归生成对象了,它就是PropertyTokenizer分词器。
public static void main(String[] args) {
Reflector reflector = new Reflector(Tokenizer.class);
token(reflector.findPropertyName("username"));
token("address.number");
token("address[1].number");
}
private static void token(String username) {
PropertyTokenizer tokenizer = new PropertyTokenizer(username);
String children = tokenizer.getChildren();
String index = tokenizer.getIndex();
String indexedName = tokenizer.getIndexedName();
String name = tokenizer.getName();
log.error("children:{} index:{} indexedName:{} name:{}",children,index,indexedName,name);
}
children:null index:null indexedName:username name:username
children:number index:null indexedName:address name:address
children:number index:1 indexedName:address[1] name:address
3、Reflector
public class Reflector {
private final Class<?> type;
private final String[] readablePropertyNames;
private final String[] writablePropertyNames;
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;
public Reflector(Class<?> clazz) {
type = clazz;
addDefaultConstructor(clazz);
addGetMethods(clazz);
addSetMethods(clazz);
addFields(clazz);
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
for (String propName : readablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
}
该类的作用是通过反射
将类clazz的相关属性提前都初始化完毕,并缓存处理。当需要类相关属性时无需手动每次反射处理,只需通过Reflector公开方法直接获取即可。