文章目录
- 前言
- 反射模块实现
- Reflector
- ReflectorFactory
- Invoker
- MetaClass
- MetaObject
- 反射模块应用
- SqlSessionFactory
- 执行SQL
前言
MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错,为了简化反射操作的相关代码,MyBatis提供了专门的反射模块,该模块位于org.apache.ibatis.reflection包下,它对常见的反射操作做了进一步的封装,提供了更加简洁方便的反射API。
反射模块实现
Reflector
Reflector是反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射需要使用的类的元信息
Reflector中提供的相关属性的含义
// 对应的Class 类型
private final Class<?> type;
// 可读属性的名称集合 可读属性就是存在 getter方法的属性,初始值为null
private final String[] readablePropertyNames;
// 可写属性的名称集合 可写属性就是存在 setter方法的属性,初始值为null
private final String[] writablePropertyNames;
// 记录了属性相应的setter方法,key是属性名称,value是Invoker方法
// 他是对setter方法对应Method对象的封装
private final Map<String, Invoker> setMethods = new HashMap<>();
// 属性相应的getter方法
private final Map<String, Invoker> getMethods = new HashMap<>();
// 记录了相应setter方法的参数类型,key是属性名称 value是setter方法的参数类型
private final Map<String, Class<?>> setTypes = new HashMap<>();
// 和上面的对应
private final Map<String, Class<?>> getTypes = new HashMap<>();
// 记录了默认的构造方法
private Constructor<?> defaultConstructor;
// 记录了所有属性名称的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
在Reflector的构造器中会完成相关的属性的初始化操作
// 解析指定的Class类型 并填充上述的集合信息
public Reflector(Class<?> clazz) {
type = clazz; // 初始化 type字段
addDefaultConstructor(clazz);// 设置默认的构造方法
addGetMethods(clazz);// 获取getter方法
addSetMethods(clazz); // 获取setter方法
addFields(clazz); // 处理没有getter/setter方法的字段
// 初始化 可读属性名称集合
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
// 初始化 可写属性名称集合
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
// caseInsensitivePropertyMap记录了所有的可读和可写属性的名称 也就是记录了所有的属性名称
for (String propName : readablePropertyNames) {
// 属性名称转大写
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
// 属性名称转大写
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
反射也可以在项目中我们直接拿来使用,定义一个普通的Bean对象。
/**
* 反射工具箱
* 测试用例
*/
public class Person {
private Integer id;
private String name;
public Person(Integer id) {
this.id = id;
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
}
Reflector中提供的公共的API方法
方法名称 | 作用 |
---|---|
getType | 获取Reflector表示的Class |
getDefaultConstructor | 获取默认的构造器 |
hasDefaultConstructor | 判断是否有默认的构造器 |
getSetInvoker | 根据属性名称获取对应的Invoker 对象 |
getGetInvoker | 根据属性名称获取对应的Invoker对象 |
getSetterType | 获取属性对应的类型 比如: String name; // getSetterType(“name”) --> java.lang.String |
getGetterType | 与上面是对应的 |
getGetablePropertyNames | 获取所有的可读属性名称的集合 |
getSetablePropertyNames | 获取所有的可写属性名称的集合 |
hasSetter | 判断是否具有某个可写的属性 |
hasGetter | 判断是否具有某个可读的属性 |
findPropertyName | 根据名称查找属性 |
ReflectorFactory
MyBatis提供了一个ReflectorFactory工厂对象,用来获取Reflector对象。
ReflectorFactory接口的定义
public interface ReflectorFactory {
// 检测该ReflectorFactory是否缓存了Reflector对象
boolean isClassCacheEnabled();
// 设置是否缓存Reflector对象
void setClassCacheEnabled(boolean classCacheEnabled);
// 创建指定了Class的Reflector对象
Reflector findForClass(Class<?> type);
}
具体实现
MyBatis只为该接口提供了DefaultReflectorFactory这一个实现类。他与Reflector的关系如下:
DefaultReflectorFactory中的实现,代码比较简单
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
// 实现对 Reflector 对象的缓存
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);
}
}
}
通过上面的介绍,我们可以具体的来使用下,加深对其的理解。
package com.domain;
public class Student {
public Integer getId() {
return 6;
}
public void setId(Integer id) {
System.out.println(id);
}
public String getUserName() {
return "张三";
}
}
这个Bean我们做了简单的处理
@Test
public void test02() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(Student.class);
System.out.println("可读属性:"+Arrays.toString(reflector.getGetablePropertyNames()));
System.out.println("可写属性:"+Arrays.toString(reflector.getSetablePropertyNames()));
System.out.println("是否具有默认的构造器:" + reflector.hasDefaultConstructor());
System.out.println("Reflector对应的Class:" + reflector.getType());
}
Invoker
针对于Class中Field和Method的调用,在MyBatis中封装了Invoker对象来统一处理(有使用到适配器模式)
/**
* @author Clinton Begin
*/
public interface Invoker {
// 执行Field或者Method
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
// 返回属性相应的类型
Class<?> getType();
}
该接口有对应的三个实现
通过上面的案例查看使用效果
package com.domain;
public class Student {
public Integer getId() {
System.out.println("读取id");
return 6;
}
public void setId(Integer id) {
System.out.println("写入id:"+id);
}
public String getUserName() {
return "张三";
}
}
测试代码
public void test03() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(Student.class);
// 获取构造器 生成对应的对象
Object o = reflector.getDefaultConstructor().newInstance();
MethodInvoker invoker1 = (MethodInvoker) reflector.getSetInvoker("id");
invoker1.invoke(o,new Object[]{999});
// 读取
Invoker invoker2 = reflector.getGetInvoker("id");
invoker2.invoke(o,null);
}
MetaClass
在Reflector中可以针对普通的属性操作,但是如果出现了比较复杂的属性,比如 private Person person; 这种,我们要查找的表达式 person.userName,针对这种表达式的处理,可以通过MetaClass来处理,通过 Reflector 和 ReflectorFactory 的组合使用实现对复杂的属性表达式的解析。
public class MetaClass {
// 缓存 Reflector
private final ReflectorFactory reflectorFactory;
// 创建 MetaClass时 会指定一个Class reflector会记录该类的相关信息
private final Reflector reflector;
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
// ....
}
准备Bean对象
public class RichType {
private RichType richType;
private Map richMap = new HashMap();
private List richList = new ArrayList() {
{
add("bar");
}
};
public RichType getRichType() {
return richType;
}
public void setRichType(RichType richType) {
this.richType = richType;
}
public List getRichList() {
return richList;
}
public void setRichList(List richList) {
this.richList = richList;
}
public Map getRichMap() {
return richMap;
}
public void setRichMap(Map richMap) {
this.richMap = richMap;
}
}
测试代码
@Test
public void test7(){
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
System.out.println(meta.hasGetter("richList"));
System.out.println(meta.hasGetter("richMap"));
System.out.println(meta.hasGetter("richList[0]"));
System.out.println(meta.hasGetter("richType"));
System.out.println(meta.hasGetter("richType.richList"));
System.out.println(meta.hasGetter("richType.richMap"));
System.out.println(meta.hasGetter("richType.richList[0]"));
System.out.println(Arrays.toString(meta.getGetterNames()));
}
MetaObject
通过MetaObject对象解析复杂的表达式来对提供的对象进行操作。
@Test
public void shouldGetAndSetField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richField", "foo");
System.out.println(meta.getValue("richField"));
}
反射模块应用
反射模块在MyBatis的核心处理层中的实际应用
SqlSessionFactory
在创建SqlSessionFactory操作的时候会完成Configuration对象的创建,而在Configuration中默认定义的ReflectorFactory的实现就是DefaultReflectorFactory对象
在解析全局配置文件的代码中,给用户提供了ReflectorFactory的扩展,也就是我们在全局配置文件中可以通过reflectorFactory标签来使用我们自定义的ReflectorFactory
执行SQL
在Statement获取结果集后,在做结果集映射的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。
在DefaultResultSetHandler的getRowValue方法中在做自动映射的时候,createAutomaticMappings对其应用。