开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第41天,点击查看活动详情
晚上开会?开始PUA了是吧
MyBatis源码基础功能
了解完MyBatis的大体功能之后,接下来看看为了支持我们操作数据库,MyBatis底层提供的一些基础工具。MyBatis依赖这些工具,通过对这些工具的封装,对外暴露简单的接口,让我们能够无感对数据库进行操作。
反射 reflection 包
通过 Java反射,能够在类的运行过程中知道这个类有哪些属性和方法,还可以修改属性、调用方法、建立类的实例。
Java反射机制主要提供了以下功能。
- 在运行时判断任意一个对象所属的类;
- 在运行时构造任意一个类的对象;
- 在运行时修改任意一个对象的成员变量;
- 在运行时调用任意一个对象的方法。
于是,我们可以先通过反射获取对象的类,从而判断两个对象是否属于同一个类;然后获取对象的成员变量,轮番比较两个对象的成员变量是否一致。reflection包下的factory子包是一个对象工厂子包,该包中的类用来基于反射生产出各种对象。首先看 ObjectFactory接口,它有以下几个方法。
void setProperties(Properties):设置工厂的属性。<T> T create(Class<T>):传入一个类型,采用无参构造方法生成这个类型的实例。<T> T create(Class<T>,List<Class<?>>,List<Object>):传入一个目标类型、一个参数类型列表、一个参数值列表,根据参数列表找到相应的含参构造方法生成这个类型的实例。<T> boolean isCollection(Class<T>):判断传入的类型是否是集合类。
而 DefaultObjectFactory 继承了 ObjectFactory 接口,是默认的对象工厂实现。作为工厂,DefaultObjectFactory的 create方法用来生产对象,而两个create方法最终都用到了instantiateClass方法。
instantiateClass方法能够通过反射找到与参数匹配的构造方法,然后基于反射调用该构造方法生成一个对象。
执行器子包
reflection 包下的 invoker 子包是执行器子包,该子包中的类能够基于反射实现对象方法的调用和对象属性的读写。这个包是为了简化我们对象方法和属性调用而存在的
invoker 子包有一个 Invoker 接口和三个实现,Invoker 接口及其实现类类图如下
Invoker接口的三个实现分别用来处理三种不同情况。
- GetFieldInvoker:负责对象属性的读操作。
- SetFieldInvoker:负责对象属性的写操作。
- MethodInvoker:负责对象其他方法的操作。
属性子包
reflection包下的 property子包是属性子包,该子包中的类用来完成与对象属性相关的操作。
PropertyNamer提供属性名称相关的操作功能,例如,通过 get、set方法的方法名找出对应的属性等。要想让 PropertyNamer 正常地发挥作用,需保证对象属性、方法的命名遵循 Java Bean的命名规范,即:
- 如果类的成员变量的名字是 abc,那么该属性对应的读写方法分别命名为getAbc()和 setAbc()。
- 如果类的属性是 boolean 类型,则允许使用“is”代替上面的“get”,读方法命名为 isAbc()。
PropertyTokenizer 是一个属性标记器。传入一个形如student[sId].name的字符串后,该标记器会将其拆分开,放入各个属性中。
对象包装器子包
reflection包下的 wrapper子包是对象包装器子包,该子包中的类使用装饰器模式对各种类型的对象(包括基本 Bean对象、集合对象、Map对象)进行进一步的封装,为其增加一些功能,使它们更易于使用。
ObjectWrapperFactory 是对象包装器工厂的接口,DefaultObjectWrapperFactory 是它的默认实现。不过该默认实现中并没有实现任何功能。MyBatis 也允许用户通过配置文件中的 objectWrapperFactory节点来注入新的 ObjectWrapperFactory。
反射核心类
reflection包中最为核心的类就是 Reflector类。Reflector 类负责对一个类进行反射解析,并将解析后的结果在属性中存储起来。
Reflector 类将一个类反射解析后,会将该类的属性、方法等一一归类放到以上的各个属性中。因此 Reflector类完成了主要的反射解析工作,这也是我们将其称为反射核心类的原因。reflection包中的其他类则多是在其反射结果的基础上进一步包装的,使整个反射功能更易用。