网站查看,域名服务dns的主要功能是,wordpress花生壳,2345网址导航周公解梦文章目录 3.4 MetaObject3.5 MetaClass 3.4 MetaObject
MetaObject是MyBatis提供的反射工具类#xff0c;可以方便地获取和设置对象的属性值。
该工具类在MyBatis源码中出现的概率非常高。
假设有两个实体类#xff1a;用户信息User和订单信息Order#xff0c;一个用户可… 文章目录 3.4 MetaObject3.5 MetaClass 3.4 MetaObject
MetaObject是MyBatis提供的反射工具类可以方便地获取和设置对象的属性值。
该工具类在MyBatis源码中出现的概率非常高。
假设有两个实体类用户信息User和订单信息Order一个用户可以有多笔订单因此User类中通过一个List对象记录用户的订单信息。
public class User {private ListOrder orderList;private Integer id;private String name;// constructor getter setter ...
}public class Order {private String orderNo;private String goodsName;// constructor getter setter ...
}下面通过一个示例研究使用MetaObject工具类获取User对象的属性信息
Test
public void testMetaObject() {ListOrder orderList new ArrayListOrder() {{add(new Order(order01, 紫金红葫芦));add(new Order(order02, 羊脂玉净瓶));}};User user new User();user.setName(银角大王);user.setOrderList(orderList);MetaObject metaObject SystemMetaObject.forObject(user);// 获取第一笔订单的名称System.out.println(metaObject.getValue(orderList[0].goodsName));// 获取第二笔订单的编号System.out.println(metaObject.getValue(orderList[1].orderNo));// 设置第二笔订单的编号metaObject.setValue(orderList[1].orderNo, order999);// 获取第二笔订单的编号System.out.println(metaObject.getValue(orderList[1].orderNo));// 判断User对象中是否有orderNo属性System.out.println(是否有orderNo属性及其getter方法 metaObject.hasGetter(orderNo));// 判断User对象中是否有name属性System.out.println(是否有name属性及其getter方法 metaObject.hasGetter(name));
}控制台打印执行结果
紫金红葫芦
order02
order999
是否有orderNo属性及其getter方法false
是否有name属性及其getter方法true由示例可知MetaObject工具类不仅可以获取对象的属性信息还能修改对象的属性。
示例代码的第一步是通过SystemMetaObject类的forObject()方法获取一个MetaObject对象。
源码1org.apache.ibatis.reflection.SystemMetaObjectpublic static MetaObject forObject(Object object) {return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY,new DefaultReflectorFactory());
}由 源码1 可知SystemMetaObject的forObject()方法会转调MetaObject的forObject()方法。
源码2org.apache.ibatis.reflection.MetaObjectpublic static MetaObject forObject(Object object, ObjectFactory objectFactory,ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {if (object null) {return SystemMetaObject.NULL_META_OBJECT;}return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,ReflectorFactory reflectorFactory) {this.originalObject object;this.objectFactory objectFactory;this.objectWrapperFactory objectWrapperFactory;this.reflectorFactory reflectorFactory;// object的类型是User因此会进入else结构中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);}
}由 源码2 可知MetaObject的forObject()方法会调用MetaObject的构造方法创建一个MetaObject实例。在构造方法中由于参数object的类型是User因此会进入else结构中创建一个BeanWrapper。 下面研究一下metaObject.getValue(orderList[0].goodsName)的执行过程。
源码3org.apache.ibatis.reflection.MetaObjectpublic Object getValue(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (!prop.hasNext()) {return objectWrapper.get(prop);}MetaObject metaValue metaObjectForProperty(prop.getIndexedName());if (metaValue SystemMetaObject.NULL_META_OBJECT) {return null;}return metaValue.getValue(prop.getChildren());
}由 源码3 可知getValue()方法的首先会构造一个PropertyTokenizer对象。
源码4org.apache.ibatis.reflection.property.PropertyTokenizerpublic class PropertyTokenizer implements IteratorPropertyTokenizer {private String name;private final String indexedName;private String index;private final String children;public PropertyTokenizer(String fullname) {// 如果属性名包含小数点则说明是查找多层属性int delim fullname.indexOf(.);if (delim -1) {// 多层属性// 则将第一层保存在name变量中剩余的保存到children变量中name fullname.substring(0, delim);children fullname.substring(delim 1);} else {// 单层属性只保存name变量children变量为空name fullname;children null;}indexedName name;// 判断第一次属性是否包含 [ 符号有的话说明该属性是个数组或集合delim name.indexOf([);if (delim -1) {// 获取索引值index name.substring(delim 1, name.length() - 1);// 获取属性名name name.substring(0, delim);}}Overridepublic boolean hasNext() {// 判断children变量是否为空return children ! null;}
}
由 源码4 可知PropertyTokenizer的构造方法会对属性名进行分析。
在示例代码中传入的fullName的值为orderList[0].goodsName包含小数点所以会进入第一个if分支最终得到name“orderList[0]”children“goodsName”indexedName“orderList[0]”。
又因为name的值包含[所以也会进入第二个if分支最终index“0”name“orderList”。 回到getValue()方法继续执行因为hasNext()方法是判断children变量是否为空显然该方法会返回true因此!prop.hasNext()为false程序不会进入if分支而是直接执行下面的metaObjectForProperty()方法传入参数indexedName“orderList[0]”。
源码5org.apache.ibatis.reflection.MetaObjectpublic MetaObject metaObjectForProperty(String name) {// 第二次执行getValue方法Object value getValue(name);return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
}由 源码5 可知metaObjectForProperty()方法会第二次调用getValue()方法但传入的参数值是orderList[0]。
它会再次创建一个PropertyTokenizer对象只是该对象持有的参数与之前的不同这次的对象中children变量为null。 由于children变量为null则!prop.hasNext()为truegetValue()方法会进入if分支执行ObjectWrapper对象的get()方法。由前面的分析可知创建的ObjectWrapper对象的类型是BeanWrapper。
源码6org.apache.ibatis.reflection.wrapper.BeanWrapperOverride
public Object get(PropertyTokenizer prop) {// 判断索引值是否为空if (prop.getIndex() ! null) {// 不为空根据Collection的方式处理Object collection resolveCollection(prop, object);return getCollectionValue(prop, collection);}// 为空按照Bean的方式处理return getBeanProperty(prop, object);
}由 源码6 可知BeanWrapper的get()方法首先判断索引值是否为空如果不为空说明是集合则根据Collection的方式处理如果为空则按照Bean的方式处理。
显然示例代码有索引值index0会进if分支根据Collection的方式处理调用resolveCollection方法
源码7org.apache.ibatis.reflection.wrapper.BaseWrapperprotected Object resolveCollection(PropertyTokenizer prop, Object object) {// prop.getName() → orderListif (.equals(prop.getName())) {return object;}return metaObject.getValue(prop.getName());
}由 源码7 可知如果prop.getName()不为空则会第三次调用MetaObject的getValue()方法。
在示例代码中此时prop.getName()的值是orderList因此不会进入if分支而是第三次调用MetaObject的getValue()方法。
它会第三次创建一个PropertyTokenizer对象只是该对象持有的参数与之前的都不同这次的对象中index和children变量均为null。 因此跟第二次一样会转调BeanWrapper的get()方法。只是这一次prop.getIndex()为null按照Bean的方式处理调用getBeanProperty()方法。
源码8org.apache.ibatis.reflection.wrapper.BeanWrapperprivate Object getBeanProperty(PropertyTokenizer prop, Object object) {try {// 利用反射机制获取属性的getter方法Invoker method metaClass.getGetInvoker(prop.getName());try {// 执行getter方法获取属性值return method.invoke(object, NO_ARGUMENTS);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} // catch ......
}由 源码8 可知getBeanProperty()方法会根据属性名利用反射机制获取该属性的getter方法再执行getter方法获取属性值。 即 源码7 中resolveCollection()方法的返回值是一个orderList集合 回到 源码7 继续执行getCollectionValue()方法
源码9org.apache.ibatis.reflection.wrapper.BaseWrapperprotected Object getCollectionValue(PropertyTokenizer prop, Object collection) {if (collection instanceof Map) {return ((Map) collection).get(prop.getIndex());}// 获取索引值int i Integer.parseInt(prop.getIndex());if (collection instanceof List) {// 强转为List集合并取得对应索引的值return ((List) collection).get(i);} else if (collection instanceof Object[]) {return ((Object[]) collection)[i];} // else if ... 其他类型的处理
}由 源码9 可知getCollectionValue()方法会判断collection参数的类型并强转为指定的类型同时还会根据索引值进行取值。示例代码中collection参数是一个List集合因此会强转为一个List集合同时索引值是0因此会返回orderList集合的索引为0的元素。
因此第三次调用MetaObject的getValue()方法的返回值就是这个索引为0的元素同时也是第二次调用getValue()方法的返回值也就是 源码5 的metaObjectForProperty()方法的第一步的返回值。 由 源码5 可知metaObjectForProperty()方法的第二步是调用MetaObject的forObject()方法创建一个MetaObject对象并将上一步查询得到Order对象作为参数传入。
程序继续执行回到了 源码3 即第一次调用MetaObject的getValue()方法。 接下来进入该方法的最后一行直接嵌套调用getValue()方法第四次传入的prop.getChildren()参数值为goodsName。
第四次调用getValue()方法首先创建一个PropertyTokenizer对象该对象属性如下 通过前面分析可知第四次调用getValue()方法最终会调用getBeanProperty()方法源码8根据属性名利用反射机制获取属性的getter方法再执行getter方法获取属性值。
示例代码中会获取goodsName属性的getter方法并调用getter方法获取属性值。 至此整个getValue()方法执行结束最终得到了orderList[0].goodsName属性的值。
简单总结getValue()方法会判断属性名是否属于多层属性是的话拆分开来获取先通过反射机制获取第一层的属性值再通过反射机制依次获取更深层的属性值。
3.5 MetaClass
MetaClass也是MyBatis提供的反射工具类。
与MetaObject不同的是MetaObject用于获取和设置对象的属性值而MetaClass用于获取类相关的信息。如判断类是否有默认构造方法判断类的属性是否有对应的Getter/Setter方法。
下面是一个MetaClass的使用示例
Test
public void testMetaClass() {MetaClass metaClass MetaClass.forClass(Order.class, new DefaultReflectorFactory());// 获取所有拥有getter方法的属性名String[] getterNames metaClass.getGetterNames();System.out.println(Arrays.toString(getterNames));// 判断是否有默认构造方法System.out.println(是否有默认构造方法 metaClass.hasDefaultConstructor());// 判断某属性是否有对应的getter/setter方法System.out.println(orderNo属性是否有对应的getter方法 metaClass.hasGetter(orderNo));System.out.println(goodsName属性是否有对应的setter方法 metaClass.hasSetter(goodsName));// 获取属性的类型System.out.println(goodsName属性的类型 metaClass.getGetterType(goodsName));// 获取属性的值Invoker invoker metaClass.getGetInvoker(orderNo);try {Object orderNo invoker.invoke(new Order(NO.1986, 《西游记》), null);System.out.println(orderNo属性的值 orderNo);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}
}控制台打印执行结果
[orderNo, goodsName]
是否有默认构造方法true
orderNo属性是否有对应的getter方法true
goodsName属性是否有对应的setter方法true
goodsName属性的类型class java.lang.String
orderNo属性的值NO.1986MetaClass工具类的源码和MetaObject类似。
…
本节完更多内容请查阅分类专栏MyBatis3源码深度解析