手写Mybatis:第8章-把反射用到出神入化

文章目录

  • 一、目标:元对象反射类
  • 二、设计:元对象反射类
  • 三、实现:元对象反射类
    • 3.1 工程结构
    • 3.2 元对象反射类关系图
    • 3.3 反射调用者
      • 3.3.1 统一调用者接口
      • 3.3.2 方法调用者
      • 3.3.3 getter 调用者
      • 3.3.4 setter 调用者
    • 3.4 属性命名和分解标记
      • 3.4.1 属性命名器
      • 3.4.2 属性分解标记
    • 3.5 反射器解耦对象
    • 3.6 元类包装反射器
    • 3.7 对象包装器 Wrapper
      • 3.7.1 对象包装器接口
      • 3.7.2 对象包装器抽象基类
      • 3.7.3 Bean 包装器
      • 3.7.4 Collection 包装器
      • 3.7.5 MapWrapper 包装器
    • 3.8 对象包装工厂
      • 3.8.1 对象包装工厂接口
      • 3.8.2 默认对象包装工厂实现类
    • 3.9 对象工厂
      • 3.9.1 对象工厂接口
      • 3.9.2 默认对象工厂实现类
    • 3.10 元对象封装
      • 3.10.1 元对象
      • 3.10.2 系统级别元对象
    • 3.11 数据源属性设置
      • 3.11.1 无池化数据源工厂
      • 3.11.2 有池化数据源工厂
  • 四、测试:元对象反射类
    • 4.1 单元测试
    • 4.2 反射类测试
      • 4.2.1 学生实体类
      • 4.2.2 老师实体类
      • 4.2.3 反射类测试
  • 五、总结:元对象反射类

一、目标:元对象反射类

💡 在实现数据源池化时,对于属性信息的获取,采用硬编码的方式。如何采取更好的方式呢?

在这里插入图片描述

  • 在数据源获取属性信息时,也就是通过 props.getproperty("driver") 等属性,都是通过手动编码的方式获取的。但是扩展性极差。
  • 如何增强扩张性呢。 Mybatis 的源码,在这里使用了 Mybatis 自己实现的元对象反射工具类,可以完成一个对象的属性的反射填充。
  • MetaObject 元对象反射工具类
    • 元对象、对象包装器、对象工厂、对象包装工厂、Reflector 反射器

二、设计:元对象反射类

💡 什么是元对象反射工具类?

  • 当需要对一个对象的所提供的属性进行统一的设置和获取值的操作。
  • 需要把当前这个被处理的对象解耦,提取出它所有的属性和方法,并按照不同的类型进行反射处理,从而包装成一个工具包。

在这里插入图片描述

  • 整个设计过程都围绕 如何拆解对象并提供反射操作 为主。
    • 对于一个对象来说,它所包括的有对象的构造函数、对象的属性、对象的方法。
    • 而对象的方法因为都是获取和设置值的操作,所以基本都是 get/set 处理,所以需要把这些方法在对象拆解的过程中摘取出来进行保存。
  • 当真正的开始操作时,则会依赖于已经实例化的对象,对其进行属性处理。
    • 而这些处理过程实际都是使用 JDK 所提供的 反射 进行操作的。
    • 而反射过程中的方法名称、入参类型都已经被我们拆解和处理了,最终使用的时候直接调用即可。

三、实现:元对象反射类

3.1 工程结构

mybatis-step-07
|-src|-main|	|-java|		|-com.lino.mybatis|			|-binding|			|	|-MapperMethod.java|			|	|-MapperProxy.java|			|	|-MapperProxyFactory.java|			|	|-MapperRegistry.java|			|-builder|			|	|-xml|			|	|	|-XMLConfigBuilder.java|			|	|-BaseBuilder.java|			|-datasource|			|	|-druid|			|	|	|-DruidDataSourceFacroty.java|			|	|-pooled|			|	|	|-PooledConnection.java|			|	|	|-PooledDataSource.java|			|	|	|-PooledDataSourceFacroty.java|			|	|	|-PoolState.java|			|	|-unpooled|			|	|	|-UnpooledDataSource.java|			|	|	|-UnpooledDataSourceFacroty.java|			|	|-DataSourceFactory.java|			|-executor|			|	|-resultset|			|	|	|-DefaultResultSetHandler.java|			|	|	|-ResultSetHandler.java|			|	|-statement|			|	|	|-BaseStatementHandler.java|			|	|	|-PreparedStatementHandler.java|			|	|	|-SimpleStatementHandler.java|			|	|	|-StatementHandler.java|			|	|-BaseExecutor.java|			|	|-Executor.java|			|	|-SimpleExecutor.java|			|-io|			|	|-Resources.java|			|-mapping|			|	|-BoundSql.java|			|	|-Environment.java|			|	|-MappedStatement.java|			|	|-ParameterMapping.java|			|	|-SqlCommandType.java|			|-reflection|			|	|-factory|			|	|	|-DefaultObjectFactory.java|			|	|	|-ObjectFactory.java|			|	|-invoker|			|	|	|-GetFieldInvoker.java|			|	|	|-Invoker.java|			|	|	|-MethodInvoker.java|			|	|	|-SetFieldInvoker.java|			|	|-property|			|	|	|-PropertyNamer.java|			|	|	|-PropertyTokenizer.java|			|	|-wrapper|			|	|	|-BaseWrapper.java|			|	|	|-BeanWrapper.java|			|	|	|-CollectionWrapper.java|			|	|	|-DefaultObjectWrapperFactory.java|			|	|	|-MapWrapper.java|			|	|	|-ObjectWrapper.java|			|	|	|-ObjectWrapperFactory.java|			|	|-MetaClass.java|			|	|-MetaObject.java|			|	|-Reflector.java|			|	|-SystemMetaObject.java|			|-session|			|	|-defaults|			|	|	|-DefaultSqlSession.java|			|	|	|-DefaultSqlSessionFactory.java|			|	|-Configuration.java|			|	|-ResultHandler.java|			|	|-SqlSession.java|			|	|-SqlSessionFactory.java|			|	|-SqlSessionFactoryBuilder.java|			|	|-TransactionIsolationLevel.java|			|-transaction|			|	|-jdbc|			|	|	|-JdbcTransaction.java|			|	|	|-JdbcTransactionFactory.java|			|	|-Transaction.java|			|	|-TransactionFactory.java|			|-type|			|	|-JdbcType.java|			|	|-TypeAliasRegistry.java|-test|-java|	|-com.lino.mybatis.test|	|-dao|	|	|-IUserDao.java|	|-po|	|	|-Student.java|	|	|-Teacher.java|	|	|-User.java|	|-ApiTest.java|	|-ReflectionTest.java|-resources|-mapper|	|-User_Mapper.xml|-mybatis-config-datasource.xml

3.2 元对象反射类关系图

在这里插入图片描述

  • Reflector 反射器类处理对象类中的 get/set 属性,包装为可调用的 Invoker 反射类。
    • 这样在对 get/set 方法反射调用时,使用方法名称获取对应的 invoke 即可 getGetInvoker(String propertyName)
  • 有了反射器的处理,之后就是对原对象的包装,由 SystemMetaObject 提供创建 MetaObject 元对象的方法。
    • 将我们需要处理的对象进行拆解和 ObjectWrapper 对象包装处理。
    • 因为一个对象的类型还需要进行一条细节的处理,以及属性信息的拆解。
    • 例如:班级[0].学生.成绩 这样的一个类中的关联类的属性,则需要进行递归的方式拆解处理后,才能设置和获取属性值。
  • 最终在 Mybatis 其他的地方,有需要属性值设定时,就可以使用反射工具包进行处理了。

3.3 反射调用者

  • 关于对象类中的属性值获取和设置可以分为 Field 字段的 get/set 还有普通的 Method 的调用。
  • 为了减少使用方的过多处理,这里可以把集中调用者的实现包装成调用策略,统一接口,不同策略,不同的实现类。

3.3.1 统一调用者接口

Invoker.java

package com.lino.mybatis.reflection.invoker;/*** @description: 调用者*/
public interface Invoker {/*** 调用** @param target 目标对象* @param args   对象数组* @return Object* @throws Exception 异常*/Object invoke(Object target, Object[] args) throws Exception;/*** 获取类的类型** @return Class<?>*/Class<?> getType();
}
  • 无论任何类型的反射调用,都离不开对象和入参,只要我们把这两个字段和返回结果定义的通用,就可以包住不同策略的实现类。

3.3.2 方法调用者

MethodInvoker.java

package com.lino.mybatis.reflection.invoker;import java.lang.reflect.Method;/*** @description: 方法调用者*/
public class MethodInvoker implements Invoker {private Class<?> type;private Method method;public MethodInvoker(Method method) {this.method = method;// 如果只有一个参数,返回参数类型,否则返回 return 类型if (method.getParameterTypes().length == 1) {type = method.getParameterTypes()[0];} else {type = method.getReturnType();}}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {return method.invoke(target, args);}@Overridepublic Class<?> getType() {return type;}
}
  • 提供方法反射调用处理,构造函数会传入对应的方法类型。

3.3.3 getter 调用者

GetFieldInvoker.java

package com.lino.mybatis.reflection.invoker;import java.lang.reflect.Field;/*** @description: getter 调用者*/
public class GetFieldInvoker implements Invoker {private Field field;public GetFieldInvoker(Field field) {this.field = field;}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {return field.get(target);}@Overridepublic Class<?> getType() {return field.getType();}
}
  • getter 方法的调用者处理,因为 get 是有返回值的,所以直接对 Field 字段操作完后直接返回结果。

3.3.4 setter 调用者

SetFieldInvoker.java

package com.lino.mybatis.reflection.invoker;import java.lang.reflect.Field;/*** @description: setter 调用者*/
public class SetFieldInvoker implements Invoker {private Field field;public SetFieldInvoker(Field field) {this.field = field;}@Overridepublic Object invoke(Object target, Object[] args) throws Exception {field.set(target, args);return null;}@Overridepublic Class<?> getType() {return field.getType();}
}
  • setter 方法的调用者处理,因为 set 只是设置值,所以这里就是返回一个 null 就可以。

3.4 属性命名和分解标记

3.4.1 属性命名器

PropertyNamer.java

package com.lino.mybatis.reflection.property;import java.util.Locale;/*** @description: 属性命名器*/
public class PropertyNamer {private PropertyNamer() {}/*** 方法转换为属性** @param name 方法名称* @return String*/public static String methodToProperty(String name) {if (name.startsWith("is")) {name = name.substring(2);} else if (name.startsWith("get") || name.startsWith("set")) {name = name.substring(3);} else {throw new RuntimeException("Error parsing property name '" + name + "'. Didn't start with 'is', 'get', 'set'.");}/*如果只有1个字母,转换为小写如果大于1个字母,第二个字母非大写,转换为小写*/if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);}return name;}/*** 开头判断get/set/is** @param name 名称* @return boolean*/public static boolean isProperty(String name) {return name.startsWith("get") || name.startsWith("set") || name.startsWith("is");}/*** 是否为getter** @param name 名称* @return boolean*/public static boolean isGetter(String name) {return name.startsWith("get") || name.startsWith("is");}/*** 是否为setter** @param name 名称* @return boolean*/public static boolean isSetter(String name) {return name.startsWith("set");}
}

3.4.2 属性分解标记

PropertyTokenizer.java

package com.lino.mybatis.reflection.property;import java.util.Iterator;/*** @description: 属性分解标记*/
public class PropertyTokenizer implements Iterable<PropertyTokenizer>, Iterator<PropertyTokenizer> {// 例子:班级[0].学生.成绩/*** 属性名称:班级*/private String name;/*** 属性对象名称:班级[0]*/private String indexedName;/*** 属性索引:0*/private String index;/*** 子属性:学生*/private String children;public PropertyTokenizer(String fullName) {// 班级[0].学生.成绩:找.int delim = fullName.indexOf(".");if (delim > -1) {name = fullName.substring(0, delim);children = fullName.substring(delim + 1);} else {// 找不到.的话,取全部部分name = fullName;children = null;}indexedName = name;// 把中括号里的数字解析出来delim = name.indexOf("[");if (delim > -1) {index = name.substring(delim + 1, name.length() - 1);name = name.substring(0, delim);}}@Overridepublic Iterator<PropertyTokenizer> iterator() {return this;}@Overridepublic boolean hasNext() {return children != null;}@Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}public String getName() {return name;}public String getIndexedName() {return indexedName;}public String getIndex() {return index;}public String getChildren() {return children;}
}

3.5 反射器解耦对象

  • Reflector 反射器专门用于解耦对象信息,只有把一个对象信息所包含的属性、方法以及关联的类都以此解析出来,才能满足后续对属性值的设置和获取。

Reflector.java

package com.lino.mybatis.reflection;import com.lino.mybatis.reflection.invoker.GetFieldInvoker;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.invoker.MethodInvoker;
import com.lino.mybatis.reflection.invoker.SetFieldInvoker;
import com.lino.mybatis.reflection.property.PropertyNamer;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;/*** @description: 反射器,属性 get/set 的映射器*/
public class Reflector {private static boolean classCacheEnabled = true;private static final String[] EMPTY_STRING_ARRAY = new String[0];/*** 线程安全的缓存*/private static final Map<Class<?>, Reflector> REFLECTOR_MAP = new ConcurrentHashMap<>();private Class<?> type;/*** get 属性列表*/private String[] readablePropertyNames = EMPTY_STRING_ARRAY;/*** set 属性列表*/private String[] writeablePropertyNames = EMPTY_STRING_ARRAY;/*** set 方法列表*/private Map<String, Invoker> setMethods = new HashMap<>(16);/*** get 方法列表*/private Map<String, Invoker> getMethods = new HashMap<>(16);/*** set 类型列表*/private Map<String, Class<?>> setTypes = new HashMap<>(16);/*** get 类型列表*/private Map<String, Class<?>> getTypes = new HashMap<>(16);/*** 构造函数*/private Constructor<?> defaultConstructor;private Map<String, String> caseInsensitivePropertyMap = new HashMap<>(16);public Reflector(Class<?> clazz) {this.type = clazz;// 加入构造函数addDefaultConstructor(clazz);// 加入getteraddGetMethods(clazz);// 加入setteraddSetMethods(clazz);// 加入字段addFields(clazz);readablePropertyNames = getMethods.keySet().toArray(new String[0]);writeablePropertyNames = setMethods.keySet().toArray(new String[0]);for (String propertyName : readablePropertyNames) {caseInsensitivePropertyMap.put(propertyName.toUpperCase(Locale.ENGLISH), propertyName);}for (String propertyName : writeablePropertyNames) {caseInsensitivePropertyMap.put(propertyName.toUpperCase(Locale.ENGLISH), propertyName);}}/*** 加入构造函数** @param clazz 对象类型*/private void addDefaultConstructor(Class<?> clazz) {Constructor<?>[] constes = clazz.getDeclaredConstructors();for (Constructor<?> constructor : constes) {if (constructor.getParameterTypes().length == 0) {if (canAccessPrivateMethods()) {try {constructor.setAccessible(true);} catch (Exception ignore) {}}if (constructor.isAccessible()) {this.defaultConstructor = constructor;}}}}/*** 加入getter方法** @param clazz 对象类型*/private void addGetMethods(Class<?> clazz) {Map<String, List<Method>> conflictingGetters = new HashMap<>(16);Method[] methods = getClassMethods(clazz);for (Method method : methods) {String name = method.getName();if (name.startsWith("get") && name.length() > 3) {if (method.getParameterTypes().length == 0) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingGetters, name, method);}} else if (name.startsWith("is") && name.length() > 2) {if (method.getParameterTypes().length == 0) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingGetters, name, method);}}}resolveGetterConflicts(conflictingGetters);}/*** 加入setter方法** @param clazz 对象类型*/private void addSetMethods(Class<?> clazz) {Map<String, List<Method>> conflictingSetters = new HashMap<>(16);Method[] methods = getClassMethods(clazz);for (Method method : methods) {String name = method.getName();if (name.startsWith("set") && name.length() > 3) {if (method.getParameterTypes().length == 1) {name = PropertyNamer.methodToProperty(name);addMethodConflict(conflictingSetters, name, method);}}}resolveSetterConflicts(conflictingSetters);}/*** 加入字段** @param clazz 对象类型*/private void addFields(Class<?> clazz) {Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (canAccessPrivateMethods()) {try {field.setAccessible(true);} catch (Exception e) {}}if (field.isAccessible()) {if (!setMethods.containsKey(field.getName())) {int modifiers = field.getModifiers();if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {addSetField(field);}}if (!getMethods.containsKey(field.getName())) {addGetField(field);}}}if (clazz.getSuperclass() != null) {addFields(clazz.getSuperclass());}}private boolean canAccessPrivateMethods() {try {SecurityManager securityManager = System.getSecurityManager();if (null != securityManager) {securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));}} catch (SecurityException e) {return false;}return true;}private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {for (String propName : conflictingGetters.keySet()) {List<Method> getters = conflictingGetters.get(propName);Iterator<Method> iterator = getters.iterator();Method firstMethod = iterator.next();if (getters.size() == 1) {addGetMethod(propName, firstMethod);} else {Method getter = firstMethod;Class<?> getterType = firstMethod.getReturnType();while (iterator.hasNext()) {Method method = iterator.next();Class<?> methodType = method.getReturnType();if (methodType.equals(getterType)) {throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");} else if (methodType.isAssignableFrom(getterType)) {// OK getter type is descendant} else if (getterType.isAssignableFrom(methodType)) {getter = method;getterType = methodType;} else {throw new RuntimeException("Illegal overloaded getter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");}}addGetMethod(propName, getter);}}}private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {for (String propName : conflictingSetters.keySet()) {List<Method> setters = conflictingSetters.get(propName);Method firstMethod = setters.get(0);if (setters.size() == 1) {addSetMethod(propName, firstMethod);} else {Class<?> expectedType = getTypes.get(propName);if (expectedType == null) {throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");} else {Iterator<Method> methods = setters.iterator();Method setter = null;while (methods.hasNext()) {Method method = methods.next();if (method.getParameterTypes().length == 1 && expectedType.equals(method.getParameterTypes()[0])) {setter = method;break;}}if (setter == null) {throw new RuntimeException("Illegal overloaded setter method with ambiguous type for property " + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");}addSetMethod(propName, setter);}}}}private boolean isValidPropertyName(String name) {return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));}private void addSetMethod(String name, Method method) {if (isValidPropertyName(name)) {setMethods.put(name, new MethodInvoker(method));setTypes.put(name, method.getParameterTypes()[0]);}}private void addGetMethod(String name, Method method) {if (isValidPropertyName(name)) {getMethods.put(name, new MethodInvoker(method));getTypes.put(name, method.getReturnType());}}private void addSetField(Field field) {if (isValidPropertyName(field.getName())) {setMethods.put(field.getName(), new SetFieldInvoker(field));setTypes.put(field.getName(), field.getType());}}private void addGetField(Field field) {if (isValidPropertyName(field.getName())) {getMethods.put(field.getName(), new GetFieldInvoker(field));getTypes.put(field.getName(), field.getType());}}private Method[] getClassMethods(Class<?> clazz) {Map<String, Method> uniqueMethods = new HashMap<>(16);Class<?> currentClass = clazz;while (currentClass != null) {addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());// 循环判断类是否是抽象类Class<?>[] interfaces = currentClass.getInterfaces();for (Class<?> anInterface : interfaces) {addUniqueMethods(uniqueMethods, anInterface.getDeclaredMethods());}currentClass = currentClass.getSuperclass();}Collection<Method> methods = uniqueMethods.values();return methods.toArray(new Method[0]);}private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {for (Method currentMethod : methods) {if (!currentMethod.isBridge()) {// 取得签名String signature = getSignature(currentMethod);// check to see if the method is already known// if it is known, then an extended class must have// overridden a methodif (!uniqueMethods.containsKey(signature)) {if (canAccessPrivateMethods()) {try {currentMethod.setAccessible(true);} catch (Exception e) {}}uniqueMethods.put(signature, currentMethod);}}}}private String getSignature(Method method) {StringBuilder sb = new StringBuilder();Class<?> returnType = method.getReturnType();if (returnType != null) {sb.append(returnType.getName()).append("#");}sb.append(method.getName());Class<?>[] parameters = method.getParameterTypes();for (int i = 0; i < parameters.length; i++) {if (i == 0) {sb.append(":");} else {sb.append(",");}sb.append(parameters[i].getName());}return sb.toString();}private void addMethodConflict(Map<String, List<Method>> conflictingGetters, String name, Method method) {List<Method> list = conflictingGetters.computeIfAbsent(name, k -> new ArrayList<>());list.add(method);}public Class<?> getType() {return type;}public Constructor<?> getDefaultConstructor() {if (defaultConstructor != null) {return defaultConstructor;} else {throw new RuntimeException("There is no default constructor for " + type);}}public boolean hasDefaultConstructor() {return defaultConstructor != null;}public Invoker getGetInvoker(String propertyName) {Invoker method = getMethods.get(propertyName);if (method == null) {throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");}return method;}public Invoker getSetInvoker(String propertyName) {Invoker method = setMethods.get(propertyName);if (method == null) {throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");}return method;}public Class<?> getSetterType(String propertyName) {Class<?> clazz = setTypes.get(propertyName);if (clazz == null) {throw new RuntimeException("There is no setter for property named '" + propertyName + "' in '" + type + "'");}return clazz;}public Class<?> getGetterType(String propertyName) {Class<?> clazz = getTypes.get(propertyName);if (clazz == null) {throw new RuntimeException("There is no getter for property named '" + propertyName + "' in '" + type + "'");}return clazz;}public String[] getGetablePropertyNames() {return readablePropertyNames;}public String[] getSetablePropertyNames() {return writeablePropertyNames;}public boolean hasSetter(String propertyName) {return setMethods.keySet().contains(propertyName);}public boolean hasGetter(String propertyName) {return getMethods.keySet().contains(propertyName);}public String findPropertyName(String name) {return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));}public static Reflector forClass(Class<?> clazz) {if (classCacheEnabled) {// 对于每个类来说,我们假设它是不会变的,这样可以考虑将这个类的信息(构造函数,getter,setter,字段)加入缓存,以提高速度Reflector cached = REFLECTOR_MAP.get(clazz);if (cached == null) {cached = new Reflector(clazz);REFLECTOR_MAP.put(clazz, cached);}return cached;} else {return new Reflector(clazz);}}public static boolean isClassCacheEnabled() {return classCacheEnabled;}public static void setClassCacheEnabled(boolean classCacheEnabled) {Reflector.classCacheEnabled = classCacheEnabled;}
}
  • Reflector 反射器类中提供了各类属性、方法、类型以及构造函数的保存操作。
  • 当调用反射器时会通过构造函数的处理,逐步从对象类中拆解出这些属性信息,便于后续反射使用。

3.6 元类包装反射器

  • Reflector 反射器类提供的是最基础的核心功能,很多方法都是私有的,为了更方便使用,还需要做一层元类的包装。
  • 在元类 MetaClass 提供必要的创建反射器以及使用反射器获取 get/setInvoker 反射方法。

MetaClass.java

package com.lino.mybatis.reflection;import com.lino.mybatis.reflection.invoker.GetFieldInvoker;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.invoker.MethodInvoker;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;/*** @description: 元类*/
public class MetaClass {private Reflector reflector;public MetaClass(Class<?> type) {this.reflector = Reflector.forClass(type);}public static MetaClass forClass(Class<?> type) {return new MetaClass(type);}public static boolean isClassCacheEnabled() {return Reflector.isClassCacheEnabled();}public static void setClassCacheEnabled(boolean classCacheEnabled) {Reflector.setClassCacheEnabled(classCacheEnabled);}public MetaClass metaClassForProperty(String name) {Class<?> propType = reflector.getGetterType(name);return MetaClass.forClass(propType);}public MetaClass metaClassForProperty(PropertyTokenizer prop) {Class<?> propType = getGetterType(prop);return MetaClass.forClass(propType);}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 String findProperty(String name) {StringBuilder prop = buildProperty(name, new StringBuilder());return prop.length() > 0 ? prop.toString() : null;}public String findProperty(String name, boolean useCameCaseMapping) {if (useCameCaseMapping) {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());}// 解析集合对象中的类型return getGetterType(prop);}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 method.getGenericReturnType();} else if (invoker instanceof GetFieldInvoker) {Field _field = GetFieldInvoker.class.getDeclaredField("field");_field.setAccessible(true);Field field = (Field) _field.get(invoker);return field.getGenericType();}} 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);}public boolean hasDefaultConstructor() {return reflector.hasDefaultConstructor();}
}
  • MetaClass 元类相当于是对我们需要处理对象的包装,解耦一个原对象,包装出一个元类、对象包装器以及对象工厂等,再组合出一个元对象。
  • 相当于说这些元类和元对象都是对我们需要操作的原对象解耦后的封装。有了这样的操作,就可以让我们处理每一个属性或者方法。

3.7 对象包装器 Wrapper

  • 对象包装器相当于是更加进一步反射调用包装处理,同时也为不同的对象类型提供不同的包装策略。
  • 再对象包装器接口中定义了更加明确的需要使用的方法,包括定义出 get/set 标准的通用方法、获取 get/set 属性名称和属性类型,以及添加属性等。

3.7.1 对象包装器接口

ObjectWrapper.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.List;/*** @description: 对象包装器*/
public interface ObjectWrapper {/*** get获取** @param prop 属性分解标记* @return Object*/Object get(PropertyTokenizer prop);/*** set设置** @param prop  属性分解标记* @param value 值*/void set(PropertyTokenizer prop, Object value);/*** 查找属性** @param name               属性名称* @param useCameCaseMapping 是否使用强制映射* @return 属性*/String findProperty(String name, boolean useCameCaseMapping);/*** 取得getter的名字列表** @return getter的名字列表*/String[] getGetterNames();/*** 取得setter的名字列表** @return setter的名字列表*/String[] getSetterNames();/*** 取得setter的类型** @param name 属性名称* @return setter的类型*/Class<?> getSetterType(String name);/*** 取得getter的类型** @param name 属性名称* @return getter的类型*/Class<?> getGetterType(String name);/*** 是否有指定的setter** @param name 属性名* @return 是否有指定的setter*/boolean hasSetter(String name);/*** 是否有指定的getter** @param name 属性名* @return 是否有指定的getter*/boolean hasGetter(String name);/*** 实例化属性** @param name          属性名* @param prop          属性分解标记* @param objectFactory 对象工厂接口* @return 元对象*/MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);/*** 是否是集合** @return boolean*/boolean isCollection();/*** 添加属性** @param element 属性对象*/void add(Object element);/*** 添加属性集合** @param elements 属性对象集合* @param <E>      属性泛型*/<E> void addAll(List<E> elements);
}
  • 后续所有实现了对象包装器接口的实现类,都需要提供这些方法实现,基本有了这些方法,也就能非常容易的处理一个对象的反射操作。
  • 方法:设置属性、获取属性、获取字段列表,获取字段类型

3.7.2 对象包装器抽象基类

BaseWrapper.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.property.PropertyTokenizer;import java.util.List;
import java.util.Map;/*** @description: 对象包装器抽象基类,提供一些工具方法* @author: lingjian* @createDate: 2022/11/9 9:55*/
public abstract class BaseWrapper implements ObjectWrapper {protected static final Object[] NO_ARGUMENTS = new Object[0];protected MetaObject metaObject;public BaseWrapper(MetaObject metaObject) {this.metaObject = metaObject;}/*** 解析集合** @param prop   属性分解标记* @param object 对象* @return Object 对象*/protected Object resolveCollection(PropertyTokenizer prop, Object object) {if ("".equals(prop.getName())) {return object;} else {return metaObject.getValue(prop.getName());}}/*** 取集合的值** @param prop       属性分解标记* @param collection 对象{Map,List/Array}* @return Object 属性对象*/protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {if (collection instanceof Map) {// map['name']return ((Map) collection).get(prop.getIndex());} else {int i = Integer.parseInt(prop.getIndex());if (collection instanceof List) {// list[0]return ((List) collection).get(i);} else if (collection instanceof Object[]) {return ((Object[]) collection)[i];} else if (collection instanceof char[]) {return ((char[]) collection)[i];} else if (collection instanceof boolean[]) {return ((boolean[]) collection)[i];} else if (collection instanceof byte[]) {return ((byte[]) collection)[i];} else if (collection instanceof double[]) {return ((double[]) collection)[i];} else if (collection instanceof float[]) {return ((float[]) collection)[i];} else if (collection instanceof int[]) {return ((int[]) collection)[i];} else if (collection instanceof long[]) {return ((long[]) collection)[i];} else if (collection instanceof short[]) {return ((short[]) collection)[i];} else {throw new RuntimeException("The '" + prop.getName() + "' property of " + collection + "is not a List or Array.");}}}/*** 设置集合的值** @param prop       属性分解标记* @param collection 对象{Map,List/Array}* @param value      值*/protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {if (collection instanceof Map) {// map['name']((Map) collection).put(prop.getIndex(), value);} else {int i = Integer.parseInt(prop.getIndex());if (collection instanceof List) {((List) collection).set(i, value);} else if (collection instanceof Object[]) {((Object[]) collection)[i] = value;} else if (collection instanceof char[]) {((char[]) collection)[i] = (Character) value;} else if (collection instanceof boolean[]) {((boolean[]) collection)[i] = (Boolean) value;} else if (collection instanceof byte[]) {((byte[]) collection)[i] = (Byte) value;} else if (collection instanceof double[]) {((double[]) collection)[i] = (Double) value;} else if (collection instanceof float[]) {((float[]) collection)[i] = (Float) value;} else if (collection instanceof int[]) {((int[]) collection)[i] = (Integer) value;} else if (collection instanceof long[]) {((long[]) collection)[i] = (Long) value;} else if (collection instanceof short[]) {((short[]) collection)[i] = (Short) value;} else {throw new RuntimeException("The '" + prop.getName() + "' property of " + collection + "is not a List or Array.");}}}
}

3.7.3 Bean 包装器

BeanWrapper.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaClass;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.invoker.Invoker;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.List;/*** @description: Bean 包装器*/
public class BeanWrapper extends BaseWrapper {/*** 原来的对象*/private Object object;/*** 元类*/private MetaClass metaClass;public BeanWrapper(MetaObject metaObject, Object object) {super(metaObject);this.object = object;this.metaClass = MetaClass.forClass(object.getClass());}@Overridepublic Object get(PropertyTokenizer prop) {// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, object);return getCollectionValue(prop, collection);} else {// 否则 getBeanPropertyreturn getBeanProperty(prop, object);}}private Object getBeanProperty(PropertyTokenizer prop, Object object) {try {// 得到getter方法,然后调用Invoker method = metaClass.getGetInvoker(prop.getName());return method.invoke(object, NO_ARGUMENTS);} catch (RuntimeException e) {throw e;} catch (Throwable t) {throw new RuntimeException("Count not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t, t);}}@Overridepublic void set(PropertyTokenizer prop, Object value) {// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, object);setCollectionValue(prop, collection, value);} else {// 否则 setBeanPropertysetBeanProperty(prop, object, value);}}private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {try {// 得到getter方法,然后调用Invoker method = metaClass.getSetInvoker(prop.getName());Object[] params = {value};method.invoke(object, params);} catch (Throwable t) {throw new RuntimeException("Count not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t, t);}}@Overridepublic String findProperty(String name, boolean useCameCaseMapping) {return metaClass.findProperty(name, useCameCaseMapping);}@Overridepublic String[] getGetterNames() {return metaClass.getGetterNames();}@Overridepublic String[] getSetterNames() {return metaClass.getSetterNames();}@Overridepublic Class<?> getSetterType(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return metaClass.getSetterType(name);} else {return metaValue.getSetterType(prop.getChildren());}} else {return metaClass.getSetterType(name);}}@Overridepublic Class<?> getGetterType(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return metaClass.getGetterType(name);} else {return metaValue.getGetterType(prop.getChildren());}} else {return metaClass.getGetterType(name);}}@Overridepublic boolean hasSetter(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {if (metaObject.hasSetter(prop.getIndexedName())) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return metaClass.hasSetter(name);} else {return metaValue.hasSetter(prop.getChildren());}} else {return false;}} else {return metaClass.hasSetter(name);}}@Overridepublic boolean hasGetter(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {if (metaObject.hasGetter(prop.getIndexedName())) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return metaClass.hasGetter(name);} else {return metaValue.hasGetter(prop.getChildren());}} else {return false;}} else {return metaClass.hasGetter(name);}}@Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {MetaObject metaValue;Class<?> type = getSetterType(prop.getName());try {Object newObject = objectFactory.create(type);metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());set(prop, newObject);} catch (Exception e) {throw new RuntimeException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on " +"instance of " + type.getName() + ". Cause: " + e, e);}return metaValue;}@Overridepublic boolean isCollection() {return false;}@Overridepublic void add(Object element) {throw new UnsupportedOperationException();}@Overridepublic <E> void addAll(List<E> elements) {throw new UnsupportedOperationException();}
}

3.7.4 Collection 包装器

CollectionWrapper.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.Collection;
import java.util.List;/*** @description: Collection 包装器*/
public class CollectionWrapper implements ObjectWrapper {/*** 原始对象*/private Collection<Object> object;public CollectionWrapper(MetaObject metaObject, Collection<Object> object) {this.object = object;}@Overridepublic Object get(PropertyTokenizer prop) {throw new UnsupportedOperationException();}@Overridepublic void set(PropertyTokenizer prop, Object value) {throw new UnsupportedOperationException();}@Overridepublic String findProperty(String name, boolean useCameCaseMapping) {throw new UnsupportedOperationException();}@Overridepublic String[] getGetterNames() {throw new UnsupportedOperationException();}@Overridepublic String[] getSetterNames() {throw new UnsupportedOperationException();}@Overridepublic Class<?> getSetterType(String name) {throw new UnsupportedOperationException();}@Overridepublic Class<?> getGetterType(String name) {throw new UnsupportedOperationException();}@Overridepublic boolean hasSetter(String name) {throw new UnsupportedOperationException();}@Overridepublic boolean hasGetter(String name) {throw new UnsupportedOperationException();}@Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {throw new UnsupportedOperationException();}@Overridepublic boolean isCollection() {return true;}@Overridepublic void add(Object element) {object.add(element);}@Overridepublic <E> void addAll(List<E> elements) {object.addAll(elements);}
}

3.7.5 MapWrapper 包装器

MapWrapper.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @description: Map 包装器*/
public class MapWrapper extends BaseWrapper {/*** 原始对象*/private Map<String, Object> map;public MapWrapper(MetaObject metaObject, Map<String, Object> map) {super(metaObject);this.map = map;}@Overridepublic Object get(PropertyTokenizer prop) {// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, map);return getCollectionValue(prop, collection);} else {return map.get(prop.getName());}}@Overridepublic void set(PropertyTokenizer prop, Object value) {// 如果有index(有中括号),说明是集合,那就要解析集合,调用的是 BaseWrapper.resolveCollection 和 getCollectionValueif (prop.getIndex() != null) {Object collection = resolveCollection(prop, map);setCollectionValue(prop, collection, value);} else {// 否则 setBeanPropertymap.put(prop.getName(), value);}}@Overridepublic String findProperty(String name, boolean useCameCaseMapping) {return name;}@Overridepublic String[] getGetterNames() {return map.keySet().toArray(new String[0]);}@Overridepublic String[] getSetterNames() {return map.keySet().toArray(new String[0]);}@Overridepublic Class<?> getSetterType(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return Object.class;} else {return metaValue.getSetterType(prop.getChildren());}} else {if (map.get(name) != null) {return map.get(name).getClass();} else {return Object.class;}}}@Overridepublic Class<?> getGetterType(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return Object.class;} else {return metaValue.getGetterType(prop.getChildren());}} else {if (map.get(name) != null) {return map.get(name).getClass();} else {return Object.class;}}}@Overridepublic boolean hasSetter(String name) {return true;}@Overridepublic boolean hasGetter(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {if (map.containsKey(prop.getIndexedName())) {MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {return true;} else {return metaValue.hasGetter(prop.getChildren());}} else {return false;}} else {return map.containsKey(prop.getName());}}@Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {HashMap<String, Object> map = new HashMap<>(16);set(prop, map);return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory());}@Overridepublic boolean isCollection() {return false;}@Overridepublic void add(Object element) {throw new UnsupportedOperationException();}@Overridepublic <E> void addAll(List<E> elements) {throw new UnsupportedOperationException();}
}

3.8 对象包装工厂

  • 通过包装工厂获取包装器

3.8.1 对象包装工厂接口

ObjectWrapperFactory.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;/*** @description: 对象包装工厂*/
public interface ObjectWrapperFactory {/*** 判断有没有包装器** @param object 对象* @return boolean*/boolean hasWrapperFor(Object object);/*** 获取包装器** @param metaObject 元对象* @param object     对象* @return 包装器*/ObjectWrapper getWrapperFor(MetaObject metaObject, Object object);
}

3.8.2 默认对象包装工厂实现类

DefaultObjectWrapperFactory.java

package com.lino.mybatis.reflection.wrapper;import com.lino.mybatis.reflection.MetaObject;/*** @description: 默认对象包装器*/
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {@Overridepublic boolean hasWrapperFor(Object object) {return false;}@Overridepublic ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {throw new RuntimeException("The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");}
}

3.9 对象工厂

3.9.1 对象工厂接口

ObjectFactory.java

package com.lino.mybatis.reflection.factory;import java.util.List;
import java.util.Properties;/*** @description: 对象工厂接口*/
public interface ObjectFactory {/*** 设置属性** @param properties 属性配置*/void setProperties(Properties properties);/*** 生产对象** @param type 对象类型* @param <T>  泛型* @return <T> 泛型对象*/<T> T create(Class<T> type);/*** 生产对象,使用指定的构造函数和构造函数参数** @param type                对象类型* @param constructorArgTypes 构造函数* @param constructorArgs     构造函数参数* @param <T>                 泛型* @return <T> 泛型对象*/<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);/*** 返回这个对象是否是集合** @param type 对象类型* @param <T>  泛型* @return 是否是集合*/<T> boolean isCollection(Class<T> type);
}

3.9.2 默认对象工厂实现类

DefaultObjectFactory.java

package com.lino.mybatis.reflection.factory;import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.*;/*** @description: 默认对象工厂,所有的对象都由工厂来生成*/
public class DefaultObjectFactory implements ObjectFactory, Serializable {private static final long serialVersionUID = -8855120656740914948L;@Overridepublic void setProperties(Properties properties) {}@Overridepublic <T> T create(Class<T> type) {return create(type, null, null);}@SuppressWarnings("unchecked")@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {// 1.解析接口Class<?> classToCreate = resolveInterface(type);// 2.类实例化return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);}private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {try {Constructor<T> constructor;// 如果没有传入constructor,调用空构造函数,核心是调用 Constructor.newInstanceif (constructorArgTypes == null || constructorArgs == null) {constructor = type.getDeclaredConstructor();if (!constructor.isAccessible()) {constructor.setAccessible(true);}return constructor.newInstance();}// 如果传入constructor,调用传入的构造函数,核心是调用 Constructor.newInstanceconstructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));if (!constructor.isAccessible()) {constructor.setAccessible(true);}return constructor.newInstance(constructorArgs.toArray(new Object[0]));} catch (Exception e) {// 如果出错,包装一下,重新抛出自己的异常StringBuilder argTypes = new StringBuilder();if (constructorArgTypes != null) {for (Class<?> argType : constructorArgTypes) {argTypes.append(argType.getSimpleName());argTypes.append(",");}}StringBuilder argValues = new StringBuilder();if (constructorArgs != null) {for (Object argType : constructorArgs) {argValues.append(argType);argTypes.append(",");}}throw new RuntimeException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). " + "Cause: " + e, e);}}/*** 解析接口,将 interface 转换为实际的 class类** @param type 对象类型* @return Class<?> 实现类*/private Class<?> resolveInterface(Class<?> type) {Class<?> classToCreate;if (type == List.class || type == Collection.class || type == Iterable.class) {// List/Collection/Iterable ---> ArrayListclassToCreate = ArrayList.class;} else if (type == Map.class) {// Map ---> HashMapclassToCreate = HashMap.class;} else if (type == SortedSet.class) {// SortedSet ---> TreeSetclassToCreate = TreeSet.class;} else if (type == Set.class) {// Set ---> HashSetclassToCreate = HashSet.class;} else {// 除此之外,就用原来的原型classToCreate = type;}return classToCreate;}@Overridepublic <T> boolean isCollection(Class<T> type) {return Collection.class.isAssignableFrom(type);}
}

3.10 元对象封装

  • 在有了反射器、元类、对象包装器以后,再使用对象工厂和对象包装工厂,就可以组合出一个完整的元对象操作类。
  • 对元对象的管理,包括:包装器策略、包装工程、统一的方法处理。

3.10.1 元对象

MetaObject.java

package com.lino.mybatis.reflection;import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.property.PropertyTokenizer;
import com.lino.mybatis.reflection.wrapper.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;/*** @description: 元对象*/
public class MetaObject {/*** 原始对象*/private Object originalObject;/*** 对象包装器*/private ObjectWrapper objectWrapper;/*** 对象工厂*/private ObjectFactory objectFactory;/*** 对象包装工厂*/private ObjectWrapperFactory objectWrapperFactory;public MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {this.originalObject = object;this.objectFactory = objectFactory;this.objectWrapperFactory = objectWrapperFactory;if (object instanceof ObjectWrapper) {// 如果对象本身已经是ObjectWrapper类型,则直接赋给objectWrapperthis.objectWrapper = (ObjectWrapper) object;} else if (objectWrapperFactory.hasWrapperFor(object)) {// 如果有包装器,调用objectWrapperFactory.getWrapperForthis.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);} else if (object instanceof Map) {// 如果是Map类型,返回MapWrapperthis.objectWrapper = new MapWrapper(this, (Map) object);} else if (object instanceof Collection) {// 如果是Collection类型,返回CollectionWrapperthis.objectWrapper = new CollectionWrapper(this, (Collection) object);} else {// 除此之外,返回 BeanWrapperthis.objectWrapper = new BeanWrapper(this, object);}}/*** 返回元对象** @param object               原始对象* @param objectFactory        对象工厂* @param objectWrapperFactory 对象包装工厂* @return MetaObject 元对象*/public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {if (object == null) {// 处理一下null,将null包装起来return SystemMetaObject.NULL_META_OBJECT;} else {return new MetaObject(object, objectFactory, objectWrapperFactory);}}public Object getOriginalObject() {return originalObject;}public ObjectWrapper getObjectWrapper() {return objectWrapper;}public ObjectFactory getObjectFactory() {return objectFactory;}public ObjectWrapperFactory getObjectWrapperFactory() {return objectWrapperFactory;}/* 以下属性委派给 ObjectWrapper *//*** 查找属性*/public String findProperty(String propName, boolean useCameCaseNapping) {return objectWrapper.findProperty(propName, useCameCaseNapping);}/*** 取得getter的名字列表*/public String[] getGetterNames() {return objectWrapper.getGetterNames();}/*** 取得setter的名字列表*/public String[] getSetterNames() {return objectWrapper.getSetterNames();}/*** 取得setter的类型*/public Class<?> getSetterType(String children) {return objectWrapper.getSetterType(children);}/*** 取得getter的类型*/public Class<?> getGetterType(String children) {return objectWrapper.getGetterType(children);}/*** 是否有指定的setter*/public boolean hasSetter(String indexedName) {return objectWrapper.hasSetter(indexedName);}/*** 是否有指定的getter*/public boolean hasGetter(String children) {return objectWrapper.hasGetter(children);}/*** 是否是集合*/public boolean isCollection() {return objectWrapper.isCollection();}/*** 添加属性*/public void add(Object element) {objectWrapper.add(element);}/*** 添加属性集合*/public <E> void addAll(List<E> elements) {objectWrapper.addAll(elements);}/*** 获取值** @param name 属性名称* @return 值*/public Object getValue(String name) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {// 如果上层是null,那就结束,返回nullreturn null;} else {// 否则继续看下一层,递归调用getValuereturn metaValue.getValue(prop.getChildren());}} else {return objectWrapper.get(prop);}}/*** 设置值** @param name  属性名* @param value 属性值*/public void setValue(String name, Object value) {PropertyTokenizer prop = new PropertyTokenizer(name);if (prop.hasNext()) {MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());if (metaValue == SystemMetaObject.NULL_META_OBJECT) {if (value == null && prop.getChildren() != null) {// 如果上层是null,还得看有没有子对象,没有就结束return;} else {// 否则还得 new 一个,委派给 objectWrapper.instantiatePropertyValuemetaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);}}// 递归调用setValuemetaValue.setValue(prop.getChildren(), value);} else {// 到最后层了,所以委派给 objectWrapper.setobjectWrapper.set(prop, value);}}/*** 为属性生成元对象** @param name 属性名* @return 元对象*/public MetaObject metaObjectForProperty(String name) {// 递归调用Object value = getValue(name);return MetaObject.forObject(value, objectFactory, objectWrapperFactory);}}
  • MetaObject 元对象算是整个服务的包装,在构造函数中提供各类对象的包装器类型的创建。
    • 包括这里提供的 getValue(String name)、setValue(String name, Object value) 等。
    • 其中当一些对象中的属性信息不是一个层次,班级[0].学生.成绩 需要被拆解后才能获取到对应的对象和属性值。

3.10.2 系统级别元对象

SystemMetaObject.java

package com.lino.mybatis.reflection;import com.lino.mybatis.reflection.factory.DefaultObjectFactory;
import com.lino.mybatis.reflection.factory.ObjectFactory;
import com.lino.mybatis.reflection.wrapper.DefaultObjectWrapperFactory;
import com.lino.mybatis.reflection.wrapper.ObjectWrapperFactory;/*** @description: 系统级别元对象*/
public class SystemMetaObject {public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(NullObject.class, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);private SystemMetaObject() {}private static class NullObject {}public static MetaObject forObject(Object object) {return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);}
}
  • 使用 SystemMetaObject#forObject 提供元对象的获取。

3.11 数据源属性设置

  • 现在有了我们实现的属性反射操作工具包,那么对于数据源中属性信息的设置,就可以使用反射来设置和获取。

3.11.1 无池化数据源工厂

UnpooledDataSourceFactory.java

package com.lino.mybatis.datasource.unpooled;import com.lino.mybatis.datasource.DataSourceFactory;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import javax.sql.DataSource;
import java.util.Properties;/*** @description: 无池化数据源工厂*/
public class UnpooledDataSourceFactory implements DataSourceFactory {protected DataSource dataSource;public UnpooledDataSourceFactory() {this.dataSource = new UnpooledDataSource();}@Overridepublic void setProperties(Properties props) {MetaObject metaObject = SystemMetaObject.forObject(dataSource);for (Object key : props.keySet()) {String propertyName = (String) key;if (metaObject.hasSetter(propertyName)) {String value = (String) props.get(propertyName);Object convertedValue = convertValue(metaObject, propertyName, value);metaObject.setValue(propertyName, convertedValue);}}}@Overridepublic DataSource getDataSource() {return dataSource;}/*** 根据setter的类型,将配置文件中的值强转成相应的类型** @param metaObject   元对象* @param propertyName 属性名* @param value        属性值* @return Object 转化后的对象*/private Object convertValue(MetaObject metaObject, String propertyName, String value) {Object convertedValue = value;Class<?> targetType = metaObject.getSetterType(propertyName);if (targetType == Integer.class || targetType == int.class) {convertedValue = Integer.valueOf(value);} else if (targetType == Long.class || targetType == long.class) {convertedValue = Long.valueOf(value);} else if (targetType == Boolean.class || targetType == boolean.class) {convertedValue = Boolean.valueOf(value);}return convertedValue;}
}
  • setProperties 方法中使用 SystemMetaObject.forObject(dataSource) 获取 DataSource 的元对象,也就是通过反射设置属性值。

3.11.2 有池化数据源工厂

PooledDataSourceFactory.java

package com.lino.mybatis.datasource.pooled;import com.lino.mybatis.datasource.unpooled.UnpooledDataSourceFactory;
import javax.sql.DataSource;/*** @description: 有连接池的数据源工厂*/
public class PooledDataSourceFactory extends UnpooledDataSourceFactory {public PooledDataSourceFactory() {this.dataSource = new PooledDataSource();}
}
  • 设置属性:继承无池化数据源工厂的属性设置。

四、测试:元对象反射类

4.1 单元测试

ApiTest.java

@Test
public void test_SqlSessionFactoryExecutor() throws IOException {// 1.从SqlSessionFactory中获取SqlSessionSqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));SqlSession sqlSession = sqlSessionFactory.openSession();// 2.获取映射器对象IUserDao userDao = sqlSession.getMapper(IUserDao.class);// 3.测试验证User user = userDao.queryUserInfoById(1L);logger.info("测试结果:{}", JSON.toJSONString(user));
}

测试结果

09:17:52.915 [main] INFO  c.l.m.d.pooled.PooledDataSource - PooledDataSource forcefully closed/removed all connections.
09:17:53.782 [main] INFO  c.l.m.d.pooled.PooledDataSource - Created connention 2104028992.
09:17:53.891 [main] INFO  com.lino.mybatis.test.ApiTest - 测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小灵哥"}

在这里插入图片描述

  • 根据单元测试和调试的截图,可以看到属性值通过反射的方式设置到对象中,满足了我们在创建数据源时的使用。

4.2 反射类测试

4.2.1 学生实体类

Student.java

package com.lino.mybatis.test.po;/*** @description: 学生类*/
public class Student {private String id;public String getId() {return id;}public void setId(String id) {this.id = id;}
}

4.2.2 老师实体类

Teacher.java

package com.lino.mybatis.test.po;import java.util.List;/*** @description: 教师类*/
public class Teacher {private String name;private double price;private List<Student> students;private Student student;public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public List<Student> getStudents() {return students;}public void setStudents(List<Student> students) {this.students = students;}public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}
}

4.2.3 反射类测试

ReflectorTest.java

package com.lino.mybatis.test;import com.alibaba.fastjson.JSON;
import com.lino.mybatis.io.Resources;
import com.lino.mybatis.reflection.MetaObject;
import com.lino.mybatis.reflection.SystemMetaObject;
import com.lino.mybatis.session.SqlSession;
import com.lino.mybatis.session.SqlSessionFactory;
import com.lino.mybatis.session.SqlSessionFactoryBuilder;
import com.lino.mybatis.test.dao.IUserDao;
import com.lino.mybatis.test.po.Student;
import com.lino.mybatis.test.po.Teacher;
import com.lino.mybatis.test.po.User;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** @description: 反射测试*/
public class ReflectionTest {private Logger logger = LoggerFactory.getLogger(ReflectionTest.class);@Testpublic void test_reflection() {Teacher teacher = new Teacher();List<Student> list = new ArrayList<>();list.add(new Student());teacher.setName("小零哥");teacher.setStudents(list);MetaObject metaObject = SystemMetaObject.forObject(teacher);logger.info("getGetterNames:{}", JSON.toJSONString(metaObject.getGetterNames()));logger.info("getSetterNames:{}", JSON.toJSONString(metaObject.getSetterNames()));logger.info("name的get方法返回值:{}", JSON.toJSONString(metaObject.getGetterType("name")));logger.info("students的set方法参数值:{}", JSON.toJSONString(metaObject.getGetterType("students")));logger.info("name的hasGetter:{}", metaObject.hasGetter("name"));logger.info("student.id(属性为对象)的hasGetter:{}", metaObject.hasGetter("student.id"));logger.info("获取name的属性值:{}", metaObject.getValue("name"));// 重新设置属性值metaObject.setValue("name", "哆啦A梦");logger.info("设置name的属性值:{}", metaObject.getValue("name"));// 设置属性(集合)的元素值metaObject.setValue("students[0].id", "001");logger.info("获取students集合的第一个元素的属性值:{}", JSON.toJSONString(metaObject.getValue("students[0].id")));logger.info("对象的序列化:{}", JSON.toJSONString(teacher));}
}

测试结果

09:23:10.154 [main] INFO  com.lino.mybatis.test.ReflectionTest - getGetterNames:["student","price","name","students"]
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - getSetterNames:["student","price","name","students"]
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - name的get方法返回值:"java.lang.String"
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - students的set方法参数值:"java.util.List"
09:23:10.156 [main] INFO  com.lino.mybatis.test.ReflectionTest - name的hasGetter:true
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - student.id(属性为对象)的hasGetter:true
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 获取name的属性值:小零哥
09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 设置name的属性值:哆啦A09:23:10.157 [main] INFO  com.lino.mybatis.test.ReflectionTest - 获取students集合的第一个元素的属性值:"001"
09:23:10.192 [main] INFO  com.lino.mybatis.test.ReflectionTest - 对象的序列化:{"name":"哆啦A梦","price":0.0,"students":[{"id":"001"}]}
  • 从测试结果看,我们拿到了对于的属性信息,并可以设置以及修改属性值,无论是单个属性还是对象属性,都可以操作。

五、总结:元对象反射类

  • 关于反射工具类的实现中,使用了大量的 JDK 所提供的关于反射一些操作,也包括可以获取一个 Class 类中的属性、字段、方法的信息。
  • 有了这些信息以后就可以按照功能流程进行解耦,把属性、反射、包装,都依次拆分出来,并按照设计原则,逐步包装让外界更少的知道内部的处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/95061.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django传递dataframe对象到前端网页

在django前端页面上展示的数据&#xff0c;还是使用django模板自带的语法 方式1 不推荐使用 直接使用 【df.to_html(indexFalse)】 使用to_html他会生成一个最基本的表格没有任何的样式&#xff0c;一点都不好看&#xff0c;如果有需要的话可以自行修改表格的样式&#xff0c;…

bazel远程缓存(Remote Cache)

原理 您可以将服务器设置为构建输出&#xff08;即这些操作输出&#xff09;的远程缓存。这些输出由输出文件名列表及其内容的哈希值组成。借助远程缓存&#xff0c;您可以重复使用其他用户的 build 中的构建输出&#xff0c;而不是在本地构建每个新输出。 增量构建极大的提升…

区块链技术与应用 - 学习笔记1【引言】

大家好&#xff0c;我是比特桃。本系列主要将我之前学习区块链技术时所做的笔记&#xff0c;进行统一的优化及整合。其中大量笔记源于视频课程&#xff1a;北京大学肖臻老师《区块链技术与应用》公开课。肖老师的课让我找回了求知若渴般的感觉&#xff0c;非常享受学习这门课的…

【大数据】Apache Iceberg 概述和源代码的构建

Apache Iceberg 概述和源代码的构建 1.数据湖的解决方案 - Iceberg1.1 Iceberg 是什么1.2 Iceberg 的 Table Format 介绍1.3 Iceberg 的核心思想1.4 Iceberg 的元数据管理1.5 Iceberg 的重要特性1.5.1 丰富的计算引擎1.5.2 灵活的文件组织形式1.5.3 优化数据入湖流程1.5.4 增量…

使用多线程std::thread发挥多核计算优势(解答)

使用多线程std::thread发挥多核计算优势&#xff08;题目&#xff09; 单核无能为力 如果我们的电脑只有一个核&#xff0c;那么我们没有什么更好的办法可以让我们的程序更快。 因为这个作业限制了你修改算法函数。你唯一能做的就是利用你电脑的多核。 使用多线程 由于我们…

国标视频云服务EasyGBS国标视频平台迁移服务器后无法启动的问题解决方法

国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入&#xff0c;并能实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。平台部署简单、可拓展性强&#xff0c;支持将接入的视频流进行全终端、全平台分发&#xff0c;分发的视频…

【力扣每日一题】2023.9.2 最多可以摧毁的敌人城堡数量

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这道题难在阅读理解&#xff0c;题目看得我匪夷所思&#xff0c;错了好多个测试用例才明白题目说的是什么。 我简单翻译一下就是寻找1和…

【ES6】JavaScript的Proxy:理解并实现高级代理功能

在JavaScript中&#xff0c;Proxy是一种能够拦截对对象的读取、设置等操作的机制。它们提供了一种方式&#xff0c;可以在执行基本操作之前或之后&#xff0c;对这些操作进行自定义处理。这种功能在许多高级编程场景中非常有用&#xff0c;比如实现数据验证、日志记录、权限控制…

【算法系列篇】模拟算法

文章目录 前言1.替换所有问号1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 提莫攻击2.1 题目要求2.2 做题思路2.3 Java代码实现 3. N 字形变换3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 外观数列4.1 题目要求4.2 做题思路4.3 Java代码实现 5. 数青蛙5.1 题目要求5.2 做题思…

【Interaction交互模块】AngularJointDrive角度关节驱动

文章目录 一、预设体位置二、案例&#xff1a;做一个“能开合的门” 1、在已建好的门框下&#xff0c;建门 2、设置参数 3、解决产生的问题 三、其它属性 一、预设体位置 交互模块——可控制物体——物理关节——角度关节驱动 二、案例&#xff1a;做一个“能…

HTML+JavaScript+CSS DIY 分隔条splitter

一、需求分析 现在电脑的屏幕越来越大&#xff0c;为了利用好宽屏&#xff0c;我们在设计系统UI时喜欢在左侧放个菜单或选项面板&#xff0c;在右边显示与菜单或选项对应的内容&#xff0c;两者之间用分隔条splitter来间隔&#xff0c;并可以通过拖动分隔条splitter来动态调研…

Scala的特质trait与java的interface接口的区别,以及Scala特质的自身类型和依赖注入

1. Scala的特质trait与java接口的区别 Scala中的特质&#xff08;trait&#xff09;和Java中的接口&#xff08;interface&#xff09;在概念和使用上有一些区别&#xff1a; 默认实现&#xff1a;在Java中&#xff0c;接口只能定义方法的签名&#xff0c;而没有默认实现。而在…