简介:MetaClass是Mybatis对类级别的元信息的封装和处理,通过与属性工具类的结合, 实现了对复杂表达式的解析,实现了获取指定描述信息的功能

  1. public class MetaClass {
  2.  
  3. private ReflectorFactory reflectorFactory;
  4. private Reflector reflector;
  5.  
  6. /**
  7. * 构造函数私有
  8. */
  9. private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
  10. this.reflectorFactory = reflectorFactory;
  11. this.reflector = reflectorFactory.findForClass(type);
  12. }
  13.  
  14. /**
  15. * 调用构造方法创建MetaClass
  16. */
  17. public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
  18. return new MetaClass(type, reflectorFactory);
  19. }
  20.  
  21. /**
  22. * 通过属性名称, 获取属性的MetaClass(解决成员变量是类的情况)
  23. */
  24. public MetaClass metaClassForProperty(String name) {
  25. Class<?> propType = reflector.getGetterType(name);
  26. return MetaClass.forClass(propType, reflectorFactory);
  27. }
  28.  
  29. public String findProperty(String name) {
  30. StringBuilder prop = buildProperty(name, new StringBuilder());
  31. return prop.length() > ? prop.toString() : null;
  32. }
  33.  
  34. public String findProperty(String name, boolean useCamelCaseMapping) {
  35. if (useCamelCaseMapping) {
  36. name = name.replace("_", "");
  37. }
  38. return findProperty(name);
  39. }
  40.  
  41. public String[] getGetterNames() {
  42. return reflector.getGetablePropertyNames();
  43. }
  44.  
  45. public String[] getSetterNames() {
  46. return reflector.getSetablePropertyNames();
  47. }
  48.  
  49. public Class<?> getSetterType(String name) {
  50. PropertyTokenizer prop = new PropertyTokenizer(name);
  51. if (prop.hasNext()) {
  52. MetaClass metaProp = metaClassForProperty(prop.getName());
  53. return metaProp.getSetterType(prop.getChildren());
  54. } else {
  55. return reflector.getSetterType(prop.getName());
  56. }
  57. }
  58.  
  59. public Class<?> getGetterType(String name) {
  60. PropertyTokenizer prop = new PropertyTokenizer(name);
  61. if (prop.hasNext()) {
  62. MetaClass metaProp = metaClassForProperty(prop);
  63. return metaProp.getGetterType(prop.getChildren());
  64. }
  65. // issue #506. Resolve the type inside a Collection Object
  66. return getGetterType(prop);
  67. }
  68.  
  69. private MetaClass metaClassForProperty(PropertyTokenizer prop) {
  70. Class<?> propType = getGetterType(prop);
  71. return MetaClass.forClass(propType, reflectorFactory);
  72. }
  73.  
  74. private Class<?> getGetterType(PropertyTokenizer prop) {
  75. Class<?> type = reflector.getGetterType(prop.getName());
  76. if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
  77. Type returnType = getGenericGetterType(prop.getName());
  78. if (returnType instanceof ParameterizedType) {
  79. Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
  80. if (actualTypeArguments != null && actualTypeArguments.length == ) {
  81. returnType = actualTypeArguments[];
  82. if (returnType instanceof Class) {
  83. type = (Class<?>) returnType;
  84. } else if (returnType instanceof ParameterizedType) {
  85. type = (Class<?>) ((ParameterizedType) returnType).getRawType();
  86. }
  87. }
  88. }
  89. }
  90. return type;
  91. }
  92.  
  93. private Type getGenericGetterType(String propertyName) {
  94. try {
  95. Invoker invoker = reflector.getGetInvoker(propertyName);
  96. if (invoker instanceof MethodInvoker) {
  97. Field _method = MethodInvoker.class.getDeclaredField("method");
  98. _method.setAccessible(true);
  99. Method method = (Method) _method.get(invoker);
  100. return TypeParameterResolver.resolveReturnType(method, reflector.getType());
  101. } else if (invoker instanceof GetFieldInvoker) {
  102. Field _field = GetFieldInvoker.class.getDeclaredField("field");
  103. _field.setAccessible(true);
  104. Field field = (Field) _field.get(invoker);
  105. return TypeParameterResolver.resolveFieldType(field, reflector.getType());
  106. }
  107. } catch (NoSuchFieldException e) {
  108. } catch (IllegalAccessException e) {
  109. }
  110. return null;
  111. }
  112.  
  113. public boolean hasSetter(String name) {
  114. PropertyTokenizer prop = new PropertyTokenizer(name);
  115. if (prop.hasNext()) {
  116. if (reflector.hasSetter(prop.getName())) {
  117. MetaClass metaProp = metaClassForProperty(prop.getName());
  118. return metaProp.hasSetter(prop.getChildren());
  119. } else {
  120. return false;
  121. }
  122. } else {
  123. return reflector.hasSetter(prop.getName());
  124. }
  125. }
  126.  
  127. public boolean hasGetter(String name) {
  128. PropertyTokenizer prop = new PropertyTokenizer(name);
  129. if (prop.hasNext()) {
  130. if (reflector.hasGetter(prop.getName())) {
  131. MetaClass metaProp = metaClassForProperty(prop);
  132. return metaProp.hasGetter(prop.getChildren());
  133. } else {
  134. return false;
  135. }
  136. } else {
  137. return reflector.hasGetter(prop.getName());
  138. }
  139. }
  140.  
  141. public Invoker getGetInvoker(String name) {
  142. return reflector.getGetInvoker(name);
  143. }
  144.  
  145. public Invoker getSetInvoker(String name) {
  146. return reflector.getSetInvoker(name);
  147. }
  148.  
  149. /**
  150. * 解析属性表达式 会去寻找reflector中是否有对应的的属性
  151. */
  152. private StringBuilder buildProperty(String name, StringBuilder builder) {
  153. // 解析属性表达式
  154. PropertyTokenizer prop = new PropertyTokenizer(name);
  155. // 是否有子表达式
  156. if (prop.hasNext()) {
  157. // 查找对应的属性
  158. String propertyName = reflector.findPropertyName(prop.getName());
  159. if (propertyName != null) {
  160. // 追加属性名
  161. builder.append(propertyName);
  162. builder.append(".");
  163. // 创建对应的 MetaClass 对象
  164. MetaClass metaProp = metaClassForProperty(propertyName);
  165. // 解析子表达式, 递归
  166. metaProp.buildProperty(prop.getChildren(), builder);
  167. }
  168. } else {
  169. // 根据名称查找属性
  170. String propertyName = reflector.findPropertyName(name);
  171. if (propertyName != null) {
  172. builder.append(propertyName);
  173. }
  174. }
  175. return builder;
  176. }
  177.  
  178. public boolean hasDefaultConstructor() {
  179. return reflector.hasDefaultConstructor();
  180. }
  181.  
  182. }

理解了这个方法(递归, 该类中有很多类似的), 就可以很好的对这个类进行理解, 以查找(richType.richProperty)为例:

  1. 通过 PropertyTokenizer 对表达式进行解析, 得到当前的 name = richType,  children = richProperty
  2. 从 reflector 中查找该 richType 属性
  3. 将 richType 添加到 builder 中
  4. 使用 metaClassForProperty 创建 richType 的 MetaClass。
  5. 递归调用自身来处理子表达式

退出的条件就是没有子表达式。 这个就是为了, 我们类中有成员变量是类, 我们可以通过其找到他们的所有类及其属性
注意, 在此过程中, ReflectorFactory 一直是同一个, 而其内部缓存了多个 Reflector 对象。

Mybatis框架基础支持层——反射工具箱之MetaClass(7)的更多相关文章

  1. Mybatis框架基础支持层——反射工具箱之Reflector&ReflectorFactory(3)

    说明:Reflector是Mybatis反射工具的基础,每个Reflector对应一个类,在Reflector中封装有该类的元信息, 以及基于类信息的一系列反射应用封装API public class ...

  2. Mybatis框架基础支持层——反射工具箱之实体属性Property工具集(6)

    本篇主要介绍mybatis反射工具中用到的三个属性工具类:PropertyTokenizer.PropertyNamer.PropertyCopier. PropertyTokenizer: 主要用来 ...

  3. Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)

    ObjectFactory官方简介:MyBatis每次创建结果集对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成. 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认 ...

  4. Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)

    简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...

  5. Mybatis框架基础支持层——日志模块(8)

    前言: java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同.为了统一这些工具的接 ...

  6. Mybatis框架基础支持层——解析器模块(2)

    解析器模块,核心类XPathParser /** * 封装了用于xml解析的类XPath.Document和EntityResolver */ public class XPathParser { / ...

  7. MyBatis源码分析-基础支持层反射模块Reflector/ReflectorFactory

    本文主要介绍MyBatis的反射模块是如何实现的. MyBatis 反射的核心类Reflector,下面我先说明它的构造函数和成员变量.具体方法下面详解. org.apache.ibatis.refl ...

  8. 精尽 MyBatis 源码分析 - 基础支持层

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  9. MyBatis 框架 基础应用

    1.ORM的概念和优势 概念: 对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据 ...

随机推荐

  1. C#线程的使用(1)

    今天刚开始学习使用线程,把学习过程与新的记录下来. 创建线程: 非常简单,只需声明她并为其提供线程起始点处的方法委托即可: 终止线程: 使用Abort和Join方法来实现: Abort方法:用于永久的 ...

  2. [微信小程序]在应用地图时,如何设置满屏(高度)

    微信小程序在做地图功能时 用常规的办法height:100%:来设置高度来占满屏幕是不行的 它不会生效 应该改用单位vh 例如 height:100vh 这样就可以是地图占满整个屏幕高度

  3. 有关promise的技巧

    其实promise的作用是将异步的代码转化为同步,这里的异步指的是request1,request2.

  4. c# 钩子类

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  5. 流媒体协议(二):RTMP协议

    一.概念与摘要 RTMP协议从属于应用层,被设计用来在适合的传输协议(如TCP)上复用和打包多媒体传输流(如音频.视频和互动内容).RTMP提供了一套全双工的可靠的多路复用消息服务,类似于TCP协议[ ...

  6. 51Nod-1006 最长公共子序列Lcs

    题目链接 Description 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca ...

  7. JVM内存知识备忘

    又是一篇备忘... 主要记录一些知识,进行一些资源的汇总. 先来群里liufor大大提供的两张图,清晰易懂: Dockerized Java https://www.youtube.com/watch ...

  8. Java:多态乃幸福本源

    01 多态是什么 在我刻板的印象里,西游记里的那段孙悟空和二郎神的精彩对战就能很好的解释“多态”这个词:一个孙悟空,能七十二变:一个二郎神,也能七十二变:他们都可以变成不同的形态,但只需要悄悄地喊一声 ...

  9. Java面试题:小白不得不懂的斐波那契数列

    很长一段时间里,我都非常疑惑:“我写的技术文章不差啊,有内容的同时还很有趣,不至于每篇只有区区几十个人读啊?为什么有些内容简单到只有一行注册码的文章浏览量反而轻松破万?”这样的疑惑如鲠在喉啊!写技术博 ...

  10. Centos 7 .Net core后台守护进程Supervisor配置

    环境: Centos 7 已安装.Net core 2.0.0  .Net core 1.1.2 1.Supervisor安装 yum 安装 yum install supervisor (阿里云验证 ...