MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错,为了简化反射操作的相关代码,MyBatis提供了专门的反射模块,该模块位于org.apache.ibatis.reflection包下,它对常见的反射操作做了进一步的封装,提供了更加简洁方便的反射API。
1.1 Reflector
Reflector是反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射需要使用的类的元信息
1.1.1 属性
首先看下Reflector类中提供的相关属性的含义
// 对应的Class 类型 1 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<>();
1.1.2 构造方法
在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对象。
1.1.3 公共的API方法
然后看看Reflector中提供的公共的API方法
方法名称 | 作用 |
getType | 获取Reflector表示的Class |
getDefaultConstructor | 获取默认的构造器 |
hasDefaultConstructor | 判断是否有默认的构造器 |
getSetInvoker | 根据属性名称获取对应的Invoker 对象 |
getGetInvoker | 根据属性名称获取对应的Invoker对象 |
getSetterType |
获取属性对应的类型 比如: |
getGetterType | 与上面是对应的 |
getGetablePropertyNames | 获取所有的可读属性名称的集合 |
getSetablePropertyNames | 获取所有的可写属性名称的集合 |
hasSetter | 判断是否具有某个可写的属性 |
hasGetter | 判断是否具有某个可读的属性 |
findPropertyName | 根据名称查找属性 |
了解了Reflector对象的基本信息后接下需要知道的就是如何来获取Reflector对象,在MyBatis中给我们提供了一个ReflectorFactory工厂对象。所以先来简单了解下ReflectorFactory对象,当然也可以直接new 出来,像上面的案例一样
1.2 ReflectorFactory
ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。
1.2.1 ReflectorFactory接口的定义
接口的定义如下
public interface ReflectorFactory { // 检测该ReflectorFactory是否缓存了Reflector对象 boolean isClassCacheEnabled(); // 设置是否缓存Reflector对象 void setClassCacheEnabled(boolean classCacheEnabled); // 创建指定了Class的Reflector对象 Reflector findForClass(Class<?> type); }
然后看看它的具体实现
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); } } }
1.2.3 使用演示
public class User implements Serializable { private Integer id; private String userName; private String realName; private String password; private Integer age; private Integer dId; private Dept dept; public Integer getId() { return 2; } public void setId(Integer id) { System.out.println(id); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getdId() { return dId; } public void setdId(Integer dId) { this.dId = dId; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } }
/** * ReflectorFactory功能演示 * @throws Exception */ @Test public void test01() throws Exception{ ReflectorFactory factory=new DefaultReflectorFactory(); Reflector reflector=factory.findForClass(User.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()); }
1.3 Invoker
针对于Class中Field和Method的调用,在MyBatis中封装了Invoker对象来统一处理(有使用到适配器模式)
1.3.1 接口说明
public interface Invoker { // 执行Field或者Method Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException; // 返回属性相应的类型 Class<?> getType(); }
这个接口对应有三个实现
1.3.2 效果演示
public class User { public Integer getId() { System.out.println("读取id"); return 6; } public void setId(Integer id) { System.out.println("写入id:"+id); } public String getUserName() { return "张三"; } }
@Test
public void test02() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(User.class);
//获取构造器 生成对应对象
Object o = reflector.getDefaultConstructor().newInstance();
org.apache.ibatis.reflection.invoker.Invoker invoker1=reflector.getSetInvoker("id");
invoker1.invoke ( o ,new Object[] { 999 });
/* 读取 */
org.apache.ibatis.reflection.invoker.Invoker invoker2= reflector.getGetInvoker("id");
invoker2.invoke( o,null);
}
}
1.4 MetaClass
在Reflector中可以针对普通的属性操作,但是如果出现了比较复杂的属性,比如 private Person person; 这种,我们要查找的表达式 person.userName.针对这种表达式的处理,这时就可以通过MetaClass来处理了。我们来看看主要的属性和构造方法
/** * 通过 Reflector 和 ReflectorFactory 的组合使用 实现对复杂的属性表达式的解析 * @author Clinton Begin */ 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); } public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) { return new MetaClass(type, reflectorFactory); } public MetaClass metaClassForProperty(String name) { Class<?> propType = reflector.getGetterType(name); return MetaClass.forClass(propType, reflectorFactory); } public String findProperty(String name) { StringBuilder prop = buildProperty(name, new StringBuilder()); return prop.length() > 0 ? prop.toString() : null; } public String findProperty(String name, boolean useCamelCaseMapping) { if (useCamelCaseMapping) { name = name.replace("_", ""); } return findProperty(name); } public String[] getGetterNames() { return reflector.getGetablePropertyNames(); } public String[] getSetterNames() { return reflector.getSetablePropertyNames(); } public Class<?> getSetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.getSetterType(prop.getChildren()); } else { return reflector.getSetterType(prop.getName()); } } public Class<?> getGetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.getGetterType(prop.getChildren()); } // issue #506. Resolve the type inside a Collection Object return getGetterType(prop); } private MetaClass metaClassForProperty(PropertyTokenizer prop) { Class<?> propType = getGetterType(prop); return MetaClass.forClass(propType, reflectorFactory); } private Class<?> getGetterType(PropertyTokenizer prop) { Class<?> type = reflector.getGetterType(prop.getName()); if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) { Type returnType = getGenericGetterType(prop.getName()); if (returnType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); if (actualTypeArguments != null && actualTypeArguments.length == 1) { returnType = actualTypeArguments[0]; if (returnType instanceof Class) { type = (Class<?>) returnType; } else if (returnType instanceof ParameterizedType) { type = (Class<?>) ((ParameterizedType) returnType).getRawType(); } } } } return type; } private Type getGenericGetterType(String propertyName) { try { Invoker invoker = reflector.getGetInvoker(propertyName); if (invoker instanceof MethodInvoker) { Field _method = MethodInvoker.class.getDeclaredField("method"); _method.setAccessible(true); Method method = (Method) _method.get(invoker); return TypeParameterResolver.resolveReturnType(method, reflector.getType()); } else if (invoker instanceof GetFieldInvoker) { Field _field = GetFieldInvoker.class.getDeclaredField("field"); _field.setAccessible(true); Field field = (Field) _field.get(invoker); return TypeParameterResolver.resolveFieldType(field, reflector.getType()); } } catch (NoSuchFieldException | IllegalAccessException ignored) { } return null; } public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (reflector.hasSetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.hasSetter(prop.getChildren()); } else { return false; } } else { return reflector.hasSetter(prop.getName()); } } public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (reflector.hasGetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.hasGetter(prop.getChildren()); } else { return false; } } else { return reflector.hasGetter(prop.getName()); } } public Invoker getGetInvoker(String name) { return reflector.getGetInvoker(name); } public Invoker getSetInvoker(String name) { return reflector.getSetInvoker(name); } private StringBuilder buildProperty(String name, StringBuilder builder) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { String propertyName = reflector.findPropertyName(prop.getName()); if (propertyName != null) { builder.append(propertyName); builder.append("."); MetaClass metaProp = metaClassForProperty(propertyName); metaProp.buildProperty(prop.getChildren(), builder); } } else { String propertyName = reflector.findPropertyName(name); if (propertyName != null) { builder.append(propertyName); } } return builder; } public boolean hasDefaultConstructor() { return reflector.hasDefaultConstructor(); } }
效果演示,准备Bean对象
public class RichType { private RichType richType; private String richField; private String richProperty; private Map richMap = new HashMap (); private List richList = new ArrayList () { { add("小家伙要记得学习"); } }; public RichType getRichType() { return richType; } public void setRichType(RichType richType) { this.richType = richType; } public String getRichProperty() { return richProperty; } public void setRichProperty(String richProperty) { this.richProperty = richProperty; } 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; } }
/** * MetaClass功能演示 * @throws Exception */ @Test public void test03() throws Exception{ ReflectorFactory factory = new DefaultReflectorFactory(); MetaClass metaClass=MetaClass.forClass ( RichType.class,factory); System.out.println(metaClass.hasGetter("richField")); System.out.println(metaClass.hasGetter("richProperty")); System.out.println(metaClass.hasGetter("richList")); System.out.println(metaClass.hasGetter("richMap")); System.out.println(metaClass.hasGetter("richList[0]")); System.out.println(metaClass.hasGetter("richType")); System.out.println(metaClass.hasGetter("richType.richField")); System.out.println(metaClass.hasGetter("richType.richProperty")); System.out.println(metaClass.hasGetter("richType.richList")); System.out.println(metaClass.hasGetter("richType.richMap")); System.out.println(metaClass.hasGetter("richType.richList[0]")); // findProperty 只能处理 . 的表达式 System.out.println(metaClass.findProperty("richType.richProperty")); System.out.println(metaClass.findProperty("richType.richProperty1")); System.out.println(metaClass.findProperty("richList[0]")); System.out.println(Arrays.toString(metaClass.getGetterNames())); }
1.5 MetaObject
可以通过MetaObject对象解析复杂的表达式来对提供的对象进行操作。具体的通过案例来演示会更直观些
@Test public void test04() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richField","李四" ); System.out.println (metaObject.getValue ( "richField" )); } @Test public void test05() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richType.richField","李四1" ); System.out.println (metaObject.getValue ( "richType.richField" )); } @Test public void test06() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richMap[0]","李四2" ); System.out.println (metaObject.getValue ( "richMap[0]" )); }
1.6 反射模块应用
看下在MyBatis的核心处理层中的实际应用
1.6.1 SqlSessionFactory
在创建SqlSessionFactory操作的时候会完成Configuration对象的创建,而在Configuration中默认定义的ReflectorFactory的实现就是DefaultReflectorFactory对象
然后在解析全局配置文件的代码中,给用户提供了ReflectorFactory的扩展,也就是我们在全局配置文件中可以通过<reflectorFactory>标签来使用我们自定义的ReflectorFactory
1.6.2 执行SQL
在Statement获取结果集后,在做结果集映射的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。
然后在DefaultResultSetHandler的getRowValue方法中在做自动映射的时候
继续跟踪,在createAutomaticMappings方法中