当前位置: 首页 > news >正文

动漫网站建设赚钱吗三端互通传奇手游开服列表

动漫网站建设赚钱吗,三端互通传奇手游开服列表,在vs中做网站,南京网站制作多少钱(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ #x1f440;#x1f440;#x1f440; 个人博客#xff1a;小奥的博客 #x1f44d;#x1f44d;#x1f44d;#xff1a;个人CSDN ⭐️⭐️⭐️#xff1a;传送门 #x1f379; 本人24应届生一枚#xff0c;技术和水平有限 个人博客小奥的博客 个人CSDN ⭐️⭐️⭐️传送门 本人24应届生一枚技术和水平有限如果文章中有不正确的内容欢迎多多指正 欢迎点赞收藏关注哟 ❤️ 文章目录 2.2 反射模块① 对象工厂子包ObjectFactory接口DefaultObjectFactory ② 执行器子包Invoker接口MethodInvokerSetFieldInvoker GetFieldInvoker ③ 属性子包PropertyCopierPropertyNamerPropertyTokenizer ④ 对象包装器子包ObjectWrapperFactoryDefaultObjectWrapperFactoryObjectWrapperBaseWrapperBeanWrapperMapWrapperCollectionWrapper ⑤ 反射核心类ReflectorReflectorFactoryDefaultReflectorFactory ⑥ 反射包装类MetaObjectMetaClassSystemMetaObject ⑦ 异常拆包工具ExceptionUtilInvocationTargetExceptionUndeclaredThrowableException ⑧ 参数名解析器⑨ 泛型解析器 2.2 反射模块 MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作Java中的反射功能虽然强大但是编码比较复杂且容易出错为了简化反射相关的代码MyBatis提供了专门的反射模块对Java原生反射进行了封装提供更加简单易用的api。 反射模块目录如下 包路径org.apache.ibatis.reflection 主要分析一下几个包中的类 对象工厂包。reflection包下的factory子包时一个对象工厂子包。该包中的类用来基于反射生产出各种对象。执行器包属性子包对象包装器包反射核心类反射包装类异常拆包工具参数名解析器泛型解析器 ① 对象工厂子包 ObjectFactory接口 ObjectFactory接口是MyBatis对象创建工厂。其默认实现是DefaultObjectFactory通过构造器反射创建对象支持无参构造和有参构造器。 /*** MyBatis uses an ObjectFactory to create all needed new Objects.* MyBatis使用ObjectFactory来创建所有需要的新对象。* author Clinton Begin*/ public interface ObjectFactory {/*** Sets configuration properties.* 设置configuration属性。* param properties* configuration properties*/default void setProperties(Properties properties) {// NOP}/*** Creates a new object with default constructor.* 使用默认构造函数创建一个新对象* param T the generic type* param type Object type* return the t*/T T create(ClassT type);/*** Creates a new object with the specified constructor and params.* 用指定的构造函数和参数创建一个新对象。* param T the generic type* param type Object type* param constructorArgTypes Constructor argument types* param constructorArgs Constructor argument values* return the t*/T T create(ClassT type, ListClass? constructorArgTypes, ListObject constructorArgs);/*** Returns true if this object can have a set of other objects. Its main purpose is to support* non-java.util.Collection objects like Scala collections.* 如果此对象可以有一组其它对象则返回true。它的主要目的是支持非java.util.Collection对象比如Scala集合。* param T the generic type* param type Object type* return whether it is a collection or not** since 3.1.0*/T boolean isCollection(ClassT type);}DefaultObjectFactory DefaultObjectFactory实现了ObjectFactory工厂接口用于创建Class类对象。 public class DefaultObjectFactory implements ObjectFactory, Serializable {private static final long serialVersionUID -8855120656740914948L;Overridepublic T T create(ClassT type) {return create(type, null, null);}SuppressWarnings(unchecked)Overridepublic T T create(ClassT type, ListClass? constructorArgTypes, ListObject constructorArgs) {Class? classToCreate resolveInterface(type); // 获得需要创建的类// we know types are assignable 类型是可赋值的// 创建指定类的的对象return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);}/*** 创建类的实例* param type 要创建实例的类* param constructorArgTypes 构造方法传入参数类型* param constructorArgs 构造方法输入参数* return* param T 实例类型*/private T T instantiateClass(ClassT type, ListClass? constructorArgTypes, ListObject constructorArgs) {try {ConstructorT constructor; // 构造方法// 参数类型列表为null或者参数列表为null即通过无参构造方法创建指定类的对象if (constructorArgTypes null || constructorArgs null) {constructor type.getDeclaredConstructor(); // 获取无参构造函数try {return constructor.newInstance(); // 使用无参构造函数创建对象} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {// 如果发生异常则修改构造函数的访问属性后再次尝试constructor.setAccessible(true);return constructor.newInstance();}throw e;}}// 根据输入参数类型查找对应的构造器即通过特定构造方法创建指定类的对象constructor type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));try {// 采用有参构造函数创建实例return constructor.newInstance(constructorArgs.toArray(new Object[0]));} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {// 如果发生异常则修改构造函数的访问属性后再次尝试constructor.setAccessible(true);return constructor.newInstance(constructorArgs.toArray(new Object[0]));}throw e;}} catch (Exception e) {// 收集所有的参数类型String argTypes Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList).stream().map(Class::getSimpleName).collect(Collectors.joining(,));// 收集所有的参数String argValues Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList).stream().map(String::valueOf).collect(Collectors.joining(,));throw new ReflectionException(Error instantiating type with invalid types ( argTypes ) or values ( argValues ). Cause: e, e);}}protected Class? resolveInterface(Class? type) {Class? classToCreate;if (type List.class || type Collection.class || type Iterable.class) {// 判断是否是集合是则返回List对象classToCreate ArrayList.class;} else if (type Map.class) {classToCreate HashMap.class; // Map类型返回HashMap对象} else if (type SortedSet.class) { // issue #510 Collections SupportclassToCreate TreeSet.class; // SortedSet类型返回TreeSet对象} else if (type Set.class) {classToCreate HashSet.class; // Set类型返回HashSet对象} else {// 如果不满足以上类型直接返回原对象classToCreate type;}return classToCreate;}Overridepublic T boolean isCollection(ClassT type) {return Collection.class.isAssignableFrom(type);}} ② 执行器子包 reflection包下的invoker子包是执行器子包该子包中的类能够基于反射实现对象方法的调用和对象属性的读写。 Invoker接口 Invoker接口用于抽象设置和读取字段值的操作。对于有getter/setter方法的字段通过MethodInvoker反射执行对应其它字段通过GetFieldInvoker和SetFieldInvoker操作Feild对象的getter/setter方法反射执行。 public interface Invoker {// 执行Field或者MethodObject invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;// 返回属性相应的属性Class? getType(); }invoker方法即执行方法。该方法负责完成对象方法的调用和对象属性的读写。在三个实现类中分别是属性读取操作、属性赋值操作、方法触发操作。getType方法用来获取类型。它对于 GetFieldInvoker和 SetFieldInvoker的含义也是明确的即获得目标属性的类型。对于MethodInvoker则是直接返回type属性。 该接口有三个实现 Invoker接口的三个实现类分别用来处理三种不同的情况 GetFieldInvoker负责对象属性的读操作SetFieldInvoker负责对象属性的写操作MethodInvoker负责对象其他方法的操作 MethodInvoker Class类中属性对应set方法或者get方法的封装。 public class MethodInvoker implements Invoker {private final Class? type; // 类型private final Method method; // 指定方法public MethodInvoker(Method method) {this.method method;// 获取属性类型if (method.getParameterTypes().length 1) {// 如果方法有且只有一个输入参数type为输入参数类型即setter方法。type method.getParameterTypes()[0];} else {// 否则type为方法返回值的类型即getter方法。type method.getReturnType();}}Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {try {return method.invoke(target, args); // 通过调用method.invoke()执行目标对象方法} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {method.setAccessible(true);return method.invoke(target, args);}throw e;}}Overridepublic Class? getType() {return type;} }MethodInvoker在其构造函数中设置set方法或者get方法并获取其参数类型或者返回值类型进行保存。 SetFieldInvoker GetFieldInvoker 没有getter/setter方法的属性使用GetFieldInvoker、SetFieldInvoker 封装了属性对应的Field对象通过调用Field.get()/set()实现获取设置属性值。 public class GetFieldInvoker implements Invoker {private final Field field; // 属性对应的Field对象public GetFieldInvoker(Field field) {this.field field;}/*** 代理方法获取目标对象的属性值。* param target 被代理的目标对象* param args 方法的参数* return 方法执行结果* throws IllegalAccessException*/Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException {try {return field.get(target); // 直接通过反射获取目标属性值} catch (IllegalAccessException e) {if (Reflector.canControlMemberAccessible()) {// 如果无法访问修改属性的访问属性field.setAccessible(true); // 将属性的可访问性修改为可访问return field.get(target); // 再次通过反射获取目标属性的值}throw e;}}// 获取属性类型Overridepublic Class? getType() {return field.getType();} }public class SetFieldInvoker implements Invoker {private final Field field; // 属性对应的Field对象public SetFieldInvoker(Field field) {this.field field;}/*** 代理方法设置目标对象的属性值* param target 被代理的目标对象* param args 方法的参数* return* throws IllegalAccessException*/Overridepublic Object invoke(Object target, Object[] args) throws IllegalAccessException {try {field.set(target, args[0]); // 设置属性值} catch (IllegalAccessException e) {// 如果无法访问if (!Reflector.canControlMemberAccessible()) {// 如果不能访问控制成员则抛出异常throw e;}// 如果可以则修改属性的访问属性field.setAccessible(true);// 再次设置目标属性的值field.set(target, args[0]);}return null;}// 获取属性类型Overridepublic Class? getType() {return field.getType();} }③ 属性子包 reflection包下的property子包是属性子包该子包中的类用来完成与对象属性相关的操作。 PropertyCopier主要用于两个对象之间的复制。PropertyNamer主要用于完成属性名和方法名之间的转化。PropertyTokenizer主要用于解析表达式比如mapper.xml中的动态sql。 PropertyCopier PropertyCopier作为属性复制器就是用来解决上述问题的借助于属性复制器PropertyCopier我们可以方便地将一个对象属性复制到另一个对象中。 User user new User(1L, 张三); User copy new User(); PropertyCopier.copyBeanProperties(user.getClass(), user, copy);输出: User{id1, name张三} User{id1, name张三}public final class PropertyCopier {private PropertyCopier() {// Prevent Instantiation of Static Class 阻止静态类的实例化}/*** 完成对象的输出复制* param type 对象的类型* param sourceBean 提供属性值的对象* param destinationBean 要被写入新属性值的对象*/public static void copyBeanProperties(Class? type, Object sourceBean, Object destinationBean) {Class? parent type; // 对象的类型while (parent ! null) {final Field[] fields parent.getDeclaredFields(); // 获取该类的所有属性不包含继承属性// 循环遍历属性进行复制for (Field field : fields) {try {try {field.set(destinationBean, field.get(sourceBean));} catch (IllegalAccessException e) {// 如果无法访问if (!Reflector.canControlMemberAccessible()) {throw e; // 如果无法访问控制成员则抛出异常}field.setAccessible(true); // 修改属性的可访问性field.set(destinationBean, field.get(sourceBean)); // 再次复制属性值}} catch (Exception e) {// Nothing useful to do, will only fail on final fields, which will be ignored.// 没有做任何有用的操作只会在final字段失败该字段将会被忽略。}}parent parent.getSuperclass();}} }copyBeanProperties方法的工作原理十分简单通过反射获取类的所有属性然后依次将这些属性值从源对象复制出来并赋给目标对象。但是要注意该属性复制器无法完成继承得来的属性的赋值因为getDeclalaredFields方法返回的属性中不包含继承属性。 PropertyNamer PropertyNamer提供属性名称相关的操作功能例如通过get、set方法的方法名找出对应的属性等。 要想让PropertyNamer正常的发挥作用需要被整对象书对象、方法的命名遵循Java Bean的命名规范。 即 如果类成员变量名字是abc那么该属性对应的读写方法分别命名为getAbc()和setAbc()。如果类的属性是boolean类型则允许使用is代替上面的get读方法命名为isAbc()。 public final class PropertyNamer {private PropertyNamer() {// Prevent Instantiation of Static Class 阻止静态类实例化}/*** 通过方法名找出对应的属性* param name 方法名* return 属性名*/public static String methodToProperty(String name) {if (name.startsWith(is)) {name name.substring(2); // 如果方法名以“is”开头即boolean类型的属性则去除“is”} else if (name.startsWith(get) || name.startsWith(set)) {name name.substring(3); // 如果方法名以“get”或者“set”开头则去除} else {// 否则抛出异常throw new ReflectionException(Error parsing property name name . Didnt start with is, get or set.);}if (name.length() 1 || name.length() 1 !Character.isUpperCase(name.charAt(1))) {// 处理get、set方法的驼峰式命名将首字母改为小写name name.substring(0, 1).toLowerCase(Locale.ENGLISH) name.substring(1);}return name;}public static boolean isProperty(String name) {return isGetter(name) || isSetter(name);}public static boolean isGetter(String name) {// 判断是否是getter方法命名。条件①以get开头并且字符串长度大于3 ②以is开头并且字符串长度大于2return name.startsWith(get) name.length() 3 || name.startsWith(is) name.length() 2;}public static boolean isSetter(String name) {// 判断是否是setter方法命名。条件以set开头并且字符串长度大于3return name.startsWith(set) name.length() 3;} }PropertyTokenizer PropertyTokenizer是一个属性标记器用于解析属性表达式传入一个形如student[sId].name的字符串后该标记器会将其拆分开放入各个属性中。拆分结束后各个属性的值如下代码注释所示 private String name; // studentprivate final String indexedName; // student[sId]private String index; // sIdprivate final String children; // namepublic class PropertyTokenizer implements IteratorPropertyTokenizer {/*** 例如表达式 student[sId].name解析器的每个字段的值如下* namestudent* indexedName student[sId]* indexsId* childrenname*/private String name; // 当前属性名private final String indexedName; // 表示带索引的属性名如果当前无索引则该值和name相同private String index; // 表示索引下标private final String children; // 去除name外的子表达式public PropertyTokenizer(String fullname) {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);}}// getter方法.../*** hasNext()、next()、remove() 实现自Iterator接口中的方法*/Overridepublic boolean hasNext() {return children ! null;}Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children); // 创建下一个PropertyTokenizer对象}Overridepublic void remove() {throw new UnsupportedOperationException(Remove is not supported, as it has no meaning in the context of properties.);} }④ 对象包装器子包 reflection包下的wrapper子包是对象包装器子包该子包中的类使用装饰器模式对各种类型的对象(包括基本的Bean对象、集合对象、Map对象)进行进一步的封装为其增加一些功能使它们更易于使用。 ObjectWrapperFactory ObjectWrapperFactory是对象包装器的工厂的接口DefaultObjectWrapperFactory是它的默认实现。不过该默认实现中并没有实现任何功能。 MyBatis允许用户通过配置文件中的objectWrapperFactory节点来注入新的ObjectWrapperFactory。 /*** 一个对象包装器创建工厂的接口定义负责将普通的Java对象包装成ObjectWrapper实例。* author Clinton Begin*/ public interface ObjectWrapperFactory {boolean hasWrapperFor(Object object); // 是否拥有指定对象的装饰对象ObjectWrapper getWrapperFor(MetaObject metaObject, Object object); // 通过对象元数据获取指定对象的包装对象 }DefaultObjectWrapperFactory ObjectWrapperFactory对象包装器工厂接口的默认实现。 /*** 默认的对象包装器工厂* author Clinton Begin*/ public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {Overridepublic boolean hasWrapperFor(Object object) {return false; // 是否用于指定对象的装饰对象默认为false}Overridepublic ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {// 通过对象元数据获取指定对象的包装对象默认不允许获取直接抛出异常。throw new ReflectionException(The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.);}}ObjectWrapper ObjectWrapper接口是所有对象包装器的总接口提供统一的包装对象的属性操作规范。 /*** 对象包装器接口定义包装对象后提供统一的属性操作方法* author Clinton Begin*/ public interface ObjectWrapper {Object get(PropertyTokenizer prop); // 获取被包装对象某个属性的值void set(PropertyTokenizer prop, Object value); // 设置被包装对象某个属性的值String findProperty(String name, boolean useCamelCaseMapping); // 查找属性名称String[] getGetterNames(); // 获取所有的属性get方法名称String[] getSetterNames(); // 获取所有的属性set方法名称Class? getSetterType(String name); // 获取指定属性的set方法的参数类型Class? getGetterType(String name); // 获取指定属性的get方法的返回类型boolean hasSetter(String name); // 是否有指定属性的set方法boolean hasGetter(String name); // 是否有指定属性的get方法/*** 实例化某个属性的值并获取对应的MetaObject对象* param name 完整的属性名* param prop 属性名描述符* param objectFactory 对象创建工厂* return 指定的属性的值对应的MetaObject对象*/MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);boolean isCollection(); // 判断被包装的对象是否是集合void add(Object element); // 往被包装的集合对象中添加新的元素 E void addAll(ListE element); // 往被包装的集合对象中添加一组元素 }因为不同的Java对象其属性操作方法也有所不同所以MyBatis默认为ObjectWrapper提供了四个实现类 BaseWrapper抽象类为子类BeanWrapper和MapWrapper提供公共的方法和属性。BeanWrapper普通对象的包装器实现类处理User这样的实体类。MapWrapper是对Map接口子类的包装。CollectionWrapper是对集合对象的包装。 BaseWrapper BaseWrapper是ObjectWrapper接口的抽象实现用于定义公共逻辑的处理方法。使用了模板设计模式。 /*** 基础包装器实现ObjectWrapper接口。* 为子类BeanWrapper和MapWrapper提供公共的方法和属性。* author Clinton Begin*/ public abstract class BaseWrapper implements ObjectWrapper {protected static final Object[] NO_ARGUMENTS {}; // 无参主要用于执行get方法所需protected final MetaObject metaObject; // 被包装对象的元数据对象protected BaseWrapper(MetaObject metaObject) {this.metaObject metaObject;}/*** 解析对象中的集合名* 根据属性表达式获取对应属性的集合(Array、List、Map)对象调用MetaObject的getValue()方法获取。* param prop PropertyTokenizer对象* param object 指定Object对象* return*/protected Object resolveCollection(PropertyTokenizer prop, Object object) {if (.equals(prop.getName())) {// 如果表达式不合法解析不到属性名则直接返回默认值return object;}// 解析到属性名调用metaObject.getValue()方法获取属性值并返回return metaObject.getValue(prop.getName());}/*** 根据属性表达式获取集合(Array、List、Map)的值* param prop PropertyTokenizer对象* param collection 集合(Array、List、Map)* return 对应下标或key的值*/protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {if (collection instanceof Map) {return ((Map) collection).get(prop.getIndex()); // 如果是Map类型则index为key}int i Integer.parseInt(prop.getIndex());// 如果是其他类型则index为下标if (collection instanceof List) {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 ReflectionException(The prop.getName() property of collection is not a List or Array.);}}/*** 根据(参数prop)设置集合(Array、List、Map)的值* param prop* param collection* param value*/protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {if (collection instanceof Map) {((Map) collection).put(prop.getIndex(), value); // 如果是Map类型则index为key} else {int i Integer.parseInt(prop.getIndex());// 如果是其他类型则index为下标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 ReflectionException(The prop.getName() property of collection is not a List or Array.);}}} }BeanWrapper /*** 普通对象包装器* 继承BaseWrapper类基于MetaClass实现Object的属性操作。* author Clinton Begin*/ public class BeanWrapper extends BaseWrapper {private final Object object; // 被包装的对象private final MetaClass metaClass; // 被包装对象所属类的元类public BeanWrapper(MetaObject metaObject, Object object) {super(metaObject);this.object object;this.metaClass MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());}/*** 获取被包装对象中对应表达式的属性值* param prop 属性表达式注意该表达式不包含子表达式* return** 如果表达式形如arr[0]/list[0]/map[key]则先获取对应属性arr/list/map对象的值再获取索引对应元素的值。* 如果表达式不带索引则传入的就是个属性名调用getBeanProperty方法获取属性对应的值。*/Overridepublic Object get(PropertyTokenizer prop) {if (prop.getIndex() ! null) {// 若存在索引信息则表示该属性表达式中的name部分为集合属性// 通过BaseWrapper中的公共方法resolveCollection获取集合对象和集合属性Object collection resolveCollection(prop, object);return getCollectionValue(prop, collection);}// 不存在索引信息则name部分为普通对象查找并调用Invoker相关方法获取属性return getBeanProperty(prop, object);}Overridepublic void set(PropertyTokenizer prop, Object value) {if (prop.getIndex() ! null) {// 若存在索引信息则表示该属性表达式中的name部分为集合属性// 通过BaseWrapper中的公共方法resolveCollection获取集合对象和集合属性Object collection resolveCollection(prop, object);setCollectionValue(prop, collection, value);} else {// 不存在索引信息则name部分为普通对象查找并调用Invoker相关方法设置属性setBeanProperty(prop, object, value);}}Overridepublic String findProperty(String name, boolean useCamelCaseMapping) {return metaClass.findProperty(name, useCamelCaseMapping);}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()) {// 不存在子表达式直接调用metaClass.getSetterType()方法获取属性类型// 这里之所以是使用metaClass.getSetterType(name)而不是metaValue.getSetterType(name)// 是因为metaValue.getSetterType也是依赖objectWrapper.getSetterType如果还是调用// metaValue.getSetterType会陷入无限递归metaClass才是递归的出口return metaClass.getSetterType(name);}// 创建MetaObject对象// 为什么优先使用MetaObject而当且仅当封装的对象为空时才使用MetaClass对象呢// MetaClass封装的是类的元信息MetaObject封装的是对象的元信息可以将类的元信息看成是对象元信息的一个子集。// 根据类元信息得到的一些类型信息可能更加具体。MetaObject metaValue metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue SystemMetaObject.NULL_META_OBJECT) {// 如果metaValue为SystemMetaObject.NULL_META_OBJECT表示封装的Java对象值为null// 通过类元信息获取set方法对应属性类型return metaClass.getSetterType(name);} else {// 当对象不为空时通过对象元信息获取set方法对应属性类型可以获得更具体的类型信息// 递归判断子表达式的children。然后返回。return metaValue.getSetterType(prop.getChildren());}}/*** 获取属性表达式对应的属性的get方法的返回类型* param name* return*/Overridepublic Class? getGetterType(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (!prop.hasNext()) {return metaClass.getGetterType(name);}MetaObject metaValue metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue SystemMetaObject.NULL_META_OBJECT) {return metaClass.getGetterType(name);} else {return metaValue.getGetterType(prop.getChildren());}}/*** 是否存在属性表达式对应的属性的set方法* param name* return*/Overridepublic boolean hasSetter(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (!prop.hasNext()) {return metaClass.hasSetter(name);}if (metaClass.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;}}/*** 是否存在表达式对应的属性的get方法 * param name* return*/Overridepublic boolean hasGetter(String name) {PropertyTokenizer prop new PropertyTokenizer(name);if (!prop.hasNext()) {return metaClass.hasGetter(name);}if (metaClass.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;}}/*** 为表达式指定的属性创建对应的MetaObject对象* param name 完整的属性名* param prop 属性名描述符* param objectFactory 对象创建工厂* return*/Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {MetaObject metaValue;Class? type getSetterType(prop.getName()); // 获取属性表达式指定属性的类型 try {Object newObject objectFactory.create(type); // 创建对应的属性对象 // 创建属性对应的MetaObject对象metaValue MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(),metaObject.getReflectorFactory());set(prop, newObject); // 为属性所属对象设置对应的属性值} catch (Exception e) {throw new ReflectionException(Cannot set value of property name because name is null and cannot be instantiated on instance of type.getName() . Cause: e.toString(), e);}return metaValue;}private Object getBeanProperty(PropertyTokenizer prop, Object object) {try {// 得到获取属性对应的Invoker对象Invoker method metaClass.getGetInvoker(prop.getName());try {return method.invoke(object, NO_ARGUMENTS); // 通过Invoker封装的反射操作获取属性值} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} catch (RuntimeException e) {throw e;} catch (Throwable t) {throw new ReflectionException(Could not get property prop.getName() from object.getClass() . Cause: t.toString(), t);}}private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {try {Invoker method metaClass.getSetInvoker(prop.getName());Object[] params { value };try {method.invoke(object, params);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} catch (Throwable t) {throw new ReflectionException(Could not set property prop.getName() of object.getClass() with value value Cause: t.toString(), t);}}Overridepublic boolean isCollection() {return false;}Overridepublic void add(Object element) {throw new UnsupportedOperationException();}Overridepublic E void addAll(ListE list) {throw new UnsupportedOperationException();} }MapWrapper /*** Map对象包装器* 继承BaseWrapper类基于Map接口方法实现对属性的操作。* author Clinton Begin*/ public class MapWrapper extends BaseWrapper {private final MapString, Object map; // 封装的Map对象public MapWrapper(MetaObject metaObject, MapString, Object map) {super(metaObject);this.map map;}Overridepublic Object get(PropertyTokenizer prop) {if (prop.getIndex() ! null) {// 存在索引信息则表示该属性表达式中的name部分为集合属性Object collection resolveCollection(prop, map);return getCollectionValue(prop, collection);}// 不存在索引信息则name部分为普通对象直接从map中获取值return map.get(prop.getName());}Overridepublic void set(PropertyTokenizer prop, Object value) {if (prop.getIndex() ! null) {// 存在索引信息则表示该属性表达式中的name部分为集合属性Object collection resolveCollection(prop, map);setCollectionValue(prop, collection, value);} else {// 不存在索引信息则name部分为普通对象直接从map中设置值map.put(prop.getName(), value);}}Overridepublic String findProperty(String name, boolean useCamelCaseMapping) {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); // 根据属性表达式创建PropertyTokenizer对象if (prop.hasNext()) {// 如果存在子表达式根据indexedName创建MetaObject对象MetaObject metaValue metaObject.metaObjectForProperty(prop.getIndexedName());if (metaValue SystemMetaObject.NULL_META_OBJECT) {return Object.class; // 如果对应的属性为null直接返回Object类型} else {// 否则子表达式由MetaObject处理return metaValue.getSetterType(prop.getChildren());}}// 没有子表达式直接map操作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());}}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()) {return map.containsKey(prop.getName());}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;}}/*** 针对嵌套属性的场景* param name 完整的属性名* param prop 属性名描述符* param objectFactory 对象创建工厂* return** 如person.name 首次设置person会创建一个key为personvalue为new HashMap()*/Overridepublic MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {HashMapString, Object map new HashMap();set(prop, map);return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(),metaObject.getReflectorFactory());}Overridepublic boolean isCollection() {return false;}Overridepublic void add(Object element) {throw new UnsupportedOperationException();}Overridepublic E void addAll(ListE element) {throw new UnsupportedOperationException();}}CollectionWrapper 集合包装器源码比较简单这里不再介绍。 ⑤ 反射核心类 reflection包中最为核心的类就是Reflector类。 Reflector MyBatis提供Reflector类来缓存类的字段名和getter/setter方法的元信息使得涉及反射的操作不再去获取这些元信息使操作更加便捷使用方式是将原始类对象Class传入其构造方法生成Reflector对象。 Reflector将一个类反射解析后会将该类的属性、方法等一一归类放到各个属性集合中。 public class Reflector {private static final MethodHandle isRecordMethodHandle getIsRecordMethodHandle();private final Class? type; // 对应的class类型private final String[] readablePropertyNames; // 可读属性的名称集合可读属性就是存在get方法的属性初始值为nullprivate final String[] writablePropertyNames; // 可写属性的名称集合可写属性就是存在set方法的属性初始值为nullprivate final MapString, Invoker setMethods new HashMap(); // 属性对应的set方法key是属性名称value是对应的set方法private final MapString, Invoker getMethods new HashMap(); // 属性对应的get方法key是属性名称value是对应的get方法// set方法输入类型。key是属性名值为对应的该属性的set方法的类型(实际为set方法的第一个参数的类型)private final MapString, Class? setTypes new HashMap();// get方法输出类型。key是属性名值为对应的该属性的get方法的类型(实际为get方法的返回值类型)private final MapString, Class? getTypes new HashMap();private Constructor? defaultConstructor; // 默认的构造方法private final MapString, String caseInsensitivePropertyMap new HashMap(); // 所有属性名称的集合key为大写的属性名称value为属性名称/*** 解析在指定的Class类型并填充上述的集合的属性即初始化相关字段* param clazz*/public Reflector(Class? clazz) {type clazz; // 初始化type字段addDefaultConstructor(clazz); // 设置默认的构造方法默认无参具体实现是通过反射遍历所有的构造方法Method[] classMethods getClassMethods(clazz); // 获取类的所有方法// 判断Class是不是record类型if (isRecord(type)) {addRecordGetMethods(classMethods);} else {addGetMethods(classMethods); // 处理所有方法中的getter方法填充getMethods集合和getTypes接口addSetMethods(classMethods); // 处理所有方法中的setter方法填充setMethods集合和setTypes接口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);}}... }从上述代码可以看到Reflector在初始化的时候会通过反射机制进行解析该类整个解析的过程并不复杂。 在Reflector的构造函数中会解析指定的Class对象并填充上述集合。Reflector.addGetMethods()方法主要解析类中定义的getter方法Reflector.addSetMethods()方法主要解析类中定义的Setter方法。 下面以addGetMethods()方法为例进行介绍。 private void addGetMethods(Method[] methods) {MapString, ListMethod conflictingGetters new HashMap();// 使用Java8的stream从所有方法中找出符合以下条件的方法(1)方法参数长度为0即无参方法 (2)符合getter方法命名规范以get开头且方法名长度大于3 或者 以is开头且方法名长度大于2Arrays.stream(methods).filter(m - m.getParameterTypes().length 0 PropertyNamer.isGetter(m.getName())).forEach(m - addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m)); // 记录方法参数类型、返回值等信息resolveGetterConflicts(conflictingGetters); // 处理重复方法名。注意一个key会有多个method的原因是当子类覆盖了父类的getter方法并且返回值发生变化时会产生两个签名不同的方法。}addGetMethods方法主要用于处理clazz的所有方法中的getter方法并填充getMethods集合和getTypes集合。 addMethodConflict()方法主要用来获取字段名和字段名对应的getter方法的映射集合并把结果保存到conflictingGetters变量中resolveGetterConflicts()方法主要用来处理方法名重复的方法。 下面简单看一下 resolveGetterConflicts()方法是如何去重的 private void resolveGetterConflicts(MapString, ListMethod conflictingGetters) {for (EntryString, ListMethod entry : conflictingGetters.entrySet()) {Method winner null;String propName entry.getKey(); // 属性名boolean isAmbiguous false;for (Method candidate : entry.getValue()) {if (winner null) {winner candidate;continue;}// 字段对应多个get方法 Class? winnerType winner.getReturnType();Class? candidateType candidate.getReturnType();if (candidateType.equals(winnerType)) { // 返回值类型相同if (!boolean.class.equals(candidateType)) {isAmbiguous true;break;}if (candidate.getName().startsWith(is)) {winner candidate; // 返回值为boolean的get方法可能有多个如getIsSave()和isSave()优先使用is开头的、更规范的方法}} else if (candidateType.isAssignableFrom(winnerType)) {// OK getter type is descendant getter类型是后代比如接口中方法的返回值是List类型子类实现方法的返回值是ArrayList这时会使用子类返回的方法。} else if (winnerType.isAssignableFrom(candidateType)) {winner candidate;} else {isAmbiguous true;break;}}addGetMethod(propName, winner, isAmbiguous); // 记录字段名对应的get方法对象和返回值类型} }去重的方式是使用更加规范的方法以及使用子类的返回值类型的方法。在确认字段名对应的唯一 getter/setter 方法后记录方法名对应的方法、参数、返回值等信息。 另外Reflector中还提供了一些公共的API方法如下表格 方法名称作用getType获取Reflector表示的ClassgetDefaultConstructor获取默认的构造器hasDefaultConstructor判断是否有默认的构造器getSetInvoker根据属性名称获取对应的Invoker 对象getGetInvoker根据属性名称获取对应的Invoker对象getSetterType获取属性对应的类型 比如String name; // getSetterType(“name”) -- java.lang.StringgetGetterType获取属性对应的类型getGetablePropertyNames获取所有的可读属性名称的集合getSetablePropertyNames获取所有的可写属性名称的集合hasSetter判断是否具有某个可写的属性hasGetter判断是否具有某个可读的属性findPropertyName根据名称查找属性 ReflectorFactory ReflectorFactory是Reflector的工厂接口而DefaultReflectorFactory是该工厂接口的默认实现。 ReflectorFactory接口主要实现了对Reflector对象的创建和缓存。 public interface ReflectorFactory {boolean isClassCacheEnabled(); // 检测该ReflectorFactory是否缓存了Reflector对象void setClassCacheEnabled(boolean classCacheEnabled); // 设置是否缓存Reflector对象Reflector findForClass(Class? type); // 创建指定了Class的Reflector对象 }具体是实现类图如下 MyBatis只为该接口提供了DefaultReflectorFactory这一个实现类。 DefaultReflectorFactory 代码比较简单主要是根据Class对象创建Reflector对象。 public class DefaultReflectorFactory implements ReflectorFactory {private boolean classCacheEnabled true; // 该字段决定是否开启对Reflector对象的缓存private final ConcurrentMapClass?, 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) { // classCacheEnabled默认为true// synchronized (type) removed see issue #461// 从缓存中获取Reflector对象如果缓存为空则创建一个新的实例放入缓存中return MapUtil.computeIfAbsent(reflectorMap, type, Reflector::new);}return new Reflector(type); // 创建一个新的Reflector实例}}⑥ 反射包装类 reflection包中存在许多的包装类它们使用装饰器模式将许多反射相关的类包装的更加简单易用。 下面介绍两个更为基础的包装类MetaClass类和MetaObject类。 MetaObject MetaObject被称为元对象是一个针对普通Object对象的反射包装类。 public class MetaObject {private final Object originalObject; // 被包装的对象的原始对象private final ObjectWrapper objectWrapper; // 原始对象的包装器private final ObjectFactory objectFactory; // 实例化对象的工厂private final ObjectWrapperFactory objectWrapperFactory; // 创建对象包装器的工厂private final ReflectorFactory reflectorFactory; // 创建Reflector对象的反射工厂private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,ReflectorFactory reflectorFactory) {this.originalObject object; // 初始化被包装对象的原始对象this.objectFactory objectFactory; // 初始化实例对象的工厂类this.objectWrapperFactory objectWrapperFactory; // 初始化创建对象包装器的工厂类this.reflectorFactory reflectorFactory; // 初始化用于获取类描述对象的工厂类// 为原始对象创建对象包装器if (object instanceof ObjectWrapper) {this.objectWrapper (ObjectWrapper) object;} else if (objectWrapperFactory.hasWrapperFor(object)) {this.objectWrapper objectWrapperFactory.getWrapperFor(this, object);} else if (object instanceof Map) {this.objectWrapper new MapWrapper(this, (Map) object);} else if (object instanceof Collection) {this.objectWrapper new CollectionWrapper(this, (Collection) object);} else {this.objectWrapper new BeanWrapper(this, object);}}... }MetaClass Class类的元数据包装Reflector基于PropertyTokenizer分词器提供对Class类的元数据各种操作可以理解成对Reflector操作的进一步增强。 其中包含了ReflectorFactory和Reflector两个字段通过PropertyTokenizer分词器提供了获取属性的名称和返回值类型等等方法也就是在Reflector上面新增了一些方法。 在Reflector中可以针对对普通属性的操作但是如果出现了比较复杂的属性比如private Person person;这种我们要查找的表达式person.userName。针对这种表达式的处理我们就可以使用MetaClass来处理了。 public class MetaClass {private final ReflectorFactory reflectorFactory; // Reflector的工厂类具有缓存Reflector对象的功能private final Reflector reflector; // 反射器用于解析和存储目标类中的元信息。创建MetaClass时会指定一个Class reflector会记录该类的相关信息private MetaClass(Class? type, ReflectorFactory reflectorFactory) {this.reflectorFactory reflectorFactory;this.reflector reflectorFactory.findForClass(type); // settings标签解析 根据类型创建Reflector}public static MetaClass forClass(Class? type, ReflectorFactory reflectorFactory) {return new MetaClass(type, reflectorFactory); // settings标签解析 调用构造方法}... } SystemMetaObject SystemMetaObject系统级的MetaObject限定了一些默认值。 public final class SystemMetaObject {// DefaultObjectFactory的单例public static final ObjectFactory DEFAULT_OBJECT_FACTORY new DefaultObjectFactory();// DefaultObjectWrapperFactory的单例public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY new DefaultObjectWrapperFactory();// 空对象的MetaObject对象单例public static final MetaObject NULL_META_OBJECT MetaObject.forObject(new NullObject(), DEFAULT_OBJECT_FACTORY,DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());private SystemMetaObject() {// Prevent Instantiation of Static Class}private static class NullObject {}/*** 创建MetaObject对象* param object 指定对象* return MetaObject对象*/public static MetaObject forObject(Object object) {return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY,new DefaultReflectorFactory());} }⑦ 异常拆包工具 ExceptionUtil ExceptionUtil是一个异常工具类它提供一个拆包异常的工具方法unwrapThrowable。 该方法将InvocationTargetException和UndeclaredThrowableException这两类异常进行拆包得到其中包含的真正的异常。 public class ExceptionUtil {private ExceptionUtil() {// Prevent Instantiation}/*** 拆解InvocationTargetException和UndeclaredThrowableException异常的包装从而得到被包装的真正异常。* param wrapped 包装后的异常 * return 拆解出的被包装异常 */public static Throwable unwrapThrowable(Throwable wrapped) {Throwable unwrapped wrapped; // 存放拆包得到的异常 while (true) {if (unwrapped instanceof InvocationTargetException) {// 拆包获得内部异常 unwrapped ((InvocationTargetException) unwrapped).getTargetException();} else if (unwrapped instanceof UndeclaredThrowableException) {// 拆包获得内部异常unwrapped ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();} else {return unwrapped; // 其他异常无需拆包}}} }unwrapThrowable方法的结构非常简单。但是我们需要思考一下为什么单独给这两个类拆包呢 下面我们看一看InvocationTargetException和UndeclaredThrowableException的源码。 InvocationTargetException为必检异常UndeclaredThrowableException为免检的运行时异常。它们都不需要MyBatis而是来自java.lang.reflect包。 InvocationTargetException 反射操作中代理类通过反射调用目标类的方法时目标类的方法可能抛出异常。发射可以调用各种目标方法因此目标方法抛出的异常是多种多样无法确定的。这意味着反射操作可能抛出一个任意类型的异常。可以使用Throwable去接收这个异常但这无疑太过宽泛。 InvocationTargetException就是为解决这个问题而设计的当反射操作的目标方法中出现异常时都统一包装成一个必检异常InvocationTargetException。 InvocationTargetException内部的target则保存了原始的异常。这样一来使得反射操作中的异常更加容易管理。 public class InvocationTargetException extends ReflectiveOperationException {private static final long serialVersionUID 4085088731926701167L;private Throwable target; // 用来保存被包装的异常protected InvocationTargetException() {super((Throwable)null); // Disallow initCause}/*** 构造方法* param target 被包装的异常 * return 异常的详细信息 */public InvocationTargetException(Throwable target) {super((Throwable)null); // Disallow initCausethis.target target;}... }UndeclaredThrowableException 根据Java的继承原则我们知道如果子类中要重写父类中的方法那么子类方法中抛出的必检异常必须是父类方法中声明过的类型。 在建立目标类的代理类时通常时建立了目标类接口的子类或者目标类的子类。因此将Java的继承原则放在代理类和被代理类上可以演化为 如果代理类和被代理类实现了共同的接口则代理方法中抛出的必检异常必须是在共同接口中声明过的如果代理类是被代理类的子类则代理类方法中抛出的必检异常必须是在被代理类的方法中声明过的。 可是在代理类中难免会在执行某些方法时抛出一些共同接口或者父类方法中没有声明的必检异常。那该怎么解决呢 如果不抛出但是它是必检异常必须抛出如果抛出则父接口或者父类中没有声明该必检异常不能抛出。 答案就是这些必检异常会被包装为免检异常 UndeclaredThrowabl eException 后抛出。 public class UndeclaredThrowableException extends RuntimeException {static final long serialVersionUID 330127114055056639L;private Throwable undeclaredThrowable; // 被包装的必检异常public UndeclaredThrowableException(Throwable undeclaredThrowable) {super((Throwable) null); // Disallow initCausethis.undeclaredThrowable undeclaredThrowable;}/*** 构造方法 * param undeclaredThrowable 被包装的必检异常* param s 异常的详细信息*/public UndeclaredThrowableException(Throwable undeclaredThrowable,String s){super(s, null); // Disallow initCausethis.undeclaredThrowable undeclaredThrowable;}... }总之InvocationTargetException 和 UndeclaredThrowableExc eption 这两个类都是异常包装类需要拆包后才能得到真正的异常类。而 ExceptionUtil的 unwrapThrowable方法就可以完成该拆包工 作。 ⑧ 参数名解析器 ParamNameResolver 是一个参数名解析器用来按顺序列出方法 中的虚参并对实参进行名称标注。 /*** 参数名解析器*/ public class ParamNameResolver {public static final String GENERIC_NAME_PREFIX param; // 自动生成的参数名前缀private final boolean useActualParamName; // 是否使用实际的参数名(通过反射获取)/*** key是索引value是参数名称。如果指定Param则从Param中获取。当不指定时将使用参数索引。* 请注意当方法具有特殊参数RowBounds或者ResultHandler时该索引可能与实际索引不同。*/// 方法输入参数的参数次序表。key为参数次序value为参数名称或者参数Param注解的值private final SortedMapInteger, String names;// 该方法输入参数中是否还有Param注解private boolean hasParamAnnotation;/*** 构造方法* 将目标方法的参数名依次列举出来。在列举的过程中如果某个参数存在Param注解则会用注解的value替换参数名。* (1)优先获取Param注解的value* (2)通过反射获取参数名* (3)使用参数下标* param config* param method*/public ParamNameResolver(Configuration config, Method method) {// 从配置对象中获取是否使用实际参数名称 setting nameuseActualParamName valuetrue / 配置this.useActualParamName config.isUseActualParamName();// 反射获取方法参数类型final Class?[] paramTypes method.getParameterTypes();// 反射获取参数注解final Annotation[][] paramAnnotations method.getParameterAnnotations();// key为参数次序value为参数名称存放参数的map容器final SortedMapInteger, String map new TreeMap();int paramCount paramAnnotations.length;// get names from Param annotationsfor (int paramIndex 0; paramIndex paramCount; paramIndex) {if (isSpecialParameter(paramTypes[paramIndex])) {// skip special parameters 跳过特殊参数/*** 跳过RowBounds和ResultHandler参数这两个参数不做解析* RowBounds处理分页 ResultHandler处理结果*/continue;}String name null;for (Annotation annotation : paramAnnotations[paramIndex]) {if (annotation instanceof Param) {hasParamAnnotation true;// 如果加了Param注解则使用value中指定的值name ((Param) annotation).value();break;}}if (name null) {// Param was not specified. 没有使用Param驻俄籍if (useActualParamName) {// 如果使用实际的参数名则通过反射获取参数名// JDK8编译类加 -parameters参数可以保留参数名称否则得到的是arg0,arg1这种无意义的参数名name getActualParamName(method, paramIndex);}if (name null) {// use the parameter index as the name (0, 1, ...)// gcode issue #71// 如果名称还是为null则可以使用下标来获取参数#{param1}, #{param2}..name String.valueOf(map.size());}}map.put(paramIndex, name);}names Collections.unmodifiableSortedMap(map); // 使其不可变}private String getActualParamName(Method method, int paramIndex) {return ParamNameUtil.getParamNames(method).get(paramIndex);}private static boolean isSpecialParameter(Class? clazz) {return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz);}public String[] getNames() {return names.values().toArray(new String[0]);}/**** 获取参数名对应的参数值* 一般是Map结构当参数只有1个时直接返回xml中写任意值都可以匹配到。*/public Object getNamedParams(Object[] args) {final int paramCount names.size(); // 参数个数if (args null || paramCount 0) {return null; // 无参情况直接返回null}if (!hasParamAnnotation paramCount 1) {// 没有Param注解且参数只有一个Object value args[names.firstKey()];// 如果参数是集合类型参数名会封装成 collection/list/arrayreturn wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null);} else {final MapString, Object param new ParamMap();int i 0;for (Map.EntryInteger, String entry : names.entrySet()) {// 参数名对应实参值param.put(entry.getValue(), args[entry.getKey()]);// add generic param names (param1, param2, ...) 额外自动生成一个参数名映射param1, param2...final String genericParamName GENERIC_NAME_PREFIX (i 1);// ensure not to overwrite parameter named with Param 确保不要覆盖以Param命名的参数if (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i;}return param;}}/*** Wrap to a {link ParamMap} if object is {link Collection} or array.* 如果对象是Collection或者数组则包装为ParamMap。* 如果是集合通过Collection访问如果是List通过List访问如果是数组通过Array访问。否则直接返回。*/public static Object wrapToMapIfCollection(Object object, String actualParamName) {if (object instanceof Collection) {ParamMapObject map new ParamMap();map.put(collection, object);if (object instanceof List) {map.put(list, object);}Optional.ofNullable(actualParamName).ifPresent(name - map.put(name, object));return map;}if (object ! null object.getClass().isArray()) {ParamMapObject map new ParamMap();map.put(array, object);Optional.ofNullable(actualParamName).ifPresent(name - map.put(name, object));return map;}return object;}}构造方法 ParamNameResolver能够将目标方法的参数名称依次列 举出来。在列举的过程中如果某个参数存在Param注解则会用注 解的 value值替换参数名。而 getNamedParams方法是在构造方法确定的 names属性和 hasPa ramAnnotation属性值的基础上给出实参的参数名。 ⑨ 泛型解析器 TypeParameterResolver类的功能是帮助MyBatis推断出属性、返回值、输入参数中泛型的具体类型。 它对外提供了三个方法 resolveFieldType解析属性的泛型resolveReturnType解析方法返回值的泛型resolveParamTypes解析方法输入参数的泛型
http://www.zqtcl.cn/news/293766/

相关文章:

  • 厦门网站建设定制多少钱wordpress能用一个数据库
  • 找人做网站需要准备什么材料怎么建设自己淘宝网站首页
  • 汽车网站建设费用js怎么做网站
  • 四川万景建设工程有限公司网站做公司网站用什么系统
  • 长沙企业建站系统3d视频制作公司
  • 长沙的网站制作公司网站建设方案的需求分析
  • 电子商务网站发展建设论文网站开发需要经过的几个主要阶段
  • 建设网站外贸做网站必须会php吗
  • 网站建设费用的请示丹徒区建设局网站
  • 上海网站制作机构个人做外贸网站违法吗
  • 咖啡厅网站开发目标汕头最新消息今天
  • 广州做外贸网站的公司简介做行业门户网站注意什么
  • 专业网页网站设计图书成都医院做网站建设
  • 浙江网站建设dyfwzx网站开发的广告词
  • 网站 seo 优化 效果中华室内设计网公众号下载
  • 如何自己建网站企业网站建站快车的优点
  • 目前做网站的公司有哪些管理系统中的计算机应用
  • 百度网站服务器企业网站报价
  • 网站后台账户如何做会计分录电商数据查询平台
  • 素材动图网站90设计app下载
  • 绍兴网站设计公司网站空间位置是什么
  • 高端网站设计品牌珠海网站建设最新报价
  • 做网站的商家怎么赚取流量费房地产怎么做网站推广
  • 企业网站建设基本流程网站积分方案
  • 网站定位与功能分析网站常见故障
  • 深圳电子商务网站制作桂林市防疫最新政策
  • 北京网站建设备案代理网站建设计划建议
  • 湛江公司做网站wordpress如何设置网站地图
  • wordpress攻防优化方案
  • 义乌市建设银行分行网站宜春静态管理