1.反射模块
MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是代码编写起来比较复杂且容易出错,为了简化反射操作的相关代码,MyBatis提供了专门的反射模块,该模块位于org.apache.ibatis.reflection包下,它对常见的反射操作做了进一步的封装,提供了更加简洁方便的反射API。
1.1 Reflector
Reflector是反射模块的基础,每个Reflector对象都对应一个类,在Reflector中缓存了反射需要使用的类的元信息
1.1.1 属性
首先看下Reflector类中提供的相关属性的含义
// 对应的Class 类型 1private final Class<?> type;// 可读属性的名称集合 可读属性就是存在 getter方法的属性,初始值为nullprivate final String[] readablePropertyNames;// 可写属性的名称集合 可写属性就是存在 setter方法的属性,初始值为nullprivate 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() {}@Overridepublic boolean isClassCacheEnabled() {return classCacheEnabled;}@Overridepublic void setClassCacheEnabled(boolean classCacheEnabled) {this.classCacheEnabled = classCacheEnabled;}@Overridepublic Reflector findForClass(Class<?> type) {if (classCacheEnabled) {// 开启缓存// synchronized (type) removed see issue #461return 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*/@Testpublic 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或者MethodObject 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 {// 缓存 Reflectorprivate 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 Objectreturn 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*/@Testpublic 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对象解析复杂的表达式来对提供的对象进行操作。具体的通过案例来演示会更直观些
@Testpublic void test04() throws Exception{RichType richType=new RichType ();MetaObject metaObject=SystemMetaObject.forObject ( richType );metaObject.setValue ( \"richField\",\"李四\" );System.out.println (metaObject.getValue ( \"richField\" ));}@Testpublic 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\" ));}@Testpublic 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方法中