mybatis源码- 反射模块一(跟着MyBatis学反射):类级别信息的封装

反射就是在运行的状态中, 对于任意的一个实体类, 都能知道这个类的所有属性和方法。 并将其封装成一个个对象, 对通过这些对象来实现对应实体类的创建, 以及访问该类的方法和属性。

在我们创建了一个Java类之后, 编译出的.class文件在虚拟机中加载, 都会在JVM中创建一个Class对象,通过该对象来创建这个类的所有对象。

在 Mybatis 中, 有对应的反射模块, 本文就是探究 mybatis 是如何进行反射的。 mybatis 中的反射主要与JavaBean相关。

1 JavaBean 规范

JavaBean 具有如下特征:

所有的属性都是私有的(通过 getter和setter 访问)

拥有公有的无参数构造函数

提供 setter/getter

实现 Serializable 接口

2 Reflector和ReflectorFactory

mybatis 这种框架, 出于性能等方面的考虑, 必然不是等到使用的时候再去解析XML/再去解析反射类。

mybatis 为每一个类提供了反射器类(Reflector), 该类中存储了反射需要使用的类的元信息。

2.1 Reflector 属性 2.1.1 属性

Reflector

从类的属性中, 我们可以看出:

一个反射器(Reflector)对应着一个 Class对象。

记录了默认构造函数

其余的是属性及其setter|getter相关

setter&getter

对于一个属性(没错, 属性, 只有有 setter|getter 才能被称之为属性)

如果是可读的(有getter方法)则Reflector会将其及其方法处理后放入对应的集合中;

如果是可写的(有setter方法), 则Reflector会将其及其方法处理后放入对应的可写相关的集合中。

最后使用 Map<String, String> caseInsensitivePropertyMap 来记录所有的属性。

2.1.2 Invoker 接口

在存储方法的时候, Reflector 使用的是 Map<String, Invoker>。 而不是 Map<String, Method>。

该接口的定义也很简单

/** * Invoker: 与方法的 invoke 相关 * @author Clinton Begin */ public interface Invoker { // 调用方法 Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException; // 获取类型 Class<?> getType(); }

定义了方法的调用和获取类型。

Invoker层次

MethodInvoker: 方法的Invoker

GetFieldInvoker: 如果没有setter, 则使用该方法, 通过Filed类直接设置成员变量的值

SetFieldInvoker: 如果没有getter, 则使用该方法, 通过Field类直接读取成员变量的值

通过该封装之后, 本来需要声明 Map<String, Method> 和 Map<String, Field> 表示的, 只需要使用 Map<String, Invoker> 即可表示。

2.2 Reflector 对外提供的方法

Reflector 对外提供的方法主要与构造函数和属性相关。

方法

构造函数:根据 Class 对象,设置 Reflector 相应的成员变量。

public Reflector(Class<?> clazz)

检查是否拥有了访问的权限:除了访问公有的变量, 还能访问 default , protected 和p rivate 变量

public static boolean canControlMemberAccessible()

查找是否有相应的属性

public String findPropertyName(String name)

获取默认的构造函数:说实话, 不清楚为啥要有这个方法, 不是可以通过 Class.newInstance() 进行创建吗?

public Constructor<?> getDefaultConstructor()

getter相关的方法

public String[] getGetablePropertyNames() // 获取所有的可读属性 public Invoker getGetInvoker(String propertyName)// 获取所有可读属性的 Invoker public Class<?> getGetterType(String propertyName)// 获取对应属性的类型 public boolean hasGetter(String propertyName)// 对应属性是否有相应的getter

对应的也有 setter 相关的方法

public String[] getSetablePropertyNames() // 获取所有的可读属性 public Invoker getSetInvoker(String propertyName)// 获取所有可读属性的 Invoker public Class<?> getSetterType(String propertyName)// 获取对应属性的类型 public boolean hasSetter(String propertyName)// 对应属性是否有相应的 setter 2.3 Reflector 私有方法 2.3.1 方法相关

每个 Relector 对应缓存一个类的元反射信息, 通过 Map 进行缓存, 后续我们在使用时就不需要再去遍历查找, 可通过键查找即可。

因此, 就涉及到几个方法

获取方法签名: 根据函数名称、参数和返回值类型来取得签名, 保证方法的唯一性

private String getSignature(Method method)

该方法获取每个方法的签名。 获取得到的签名

返回值类型#方法名:参数1,参数2,参数3...

很显然, 签名的目的是唯一性。 那使用语言本身的特性来保证唯一性是最好的:

方法名不一致, 则方法就不一致

返回值不一致或者不是其子类, 则方法不一致

参数数量, 参数类型顺序不一致方法也会不一样

因此, 以上的签名方式可以保证方法的唯一性。

获取类的所有方法

private Method[] getClassMethods(Class<?> cls)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwdzy.html