(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨
👀👀👀 个人博客:小奥的博客
👍👍👍:个人优快云
⭐️⭐️⭐️:传送门
🍹 本人24应届生一枚,技术和水平有限,如果文章中有不正确的内容,欢迎多多指正!
📜 欢迎点赞收藏关注哟! ❤️
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(Class<T> 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(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
/**
* Returns true if this object can have a set of other objects. It's 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(Class<T> type);
}
DefaultObjectFactory
DefaultObjectFactory,实现了ObjectFactory工厂接口,用于创建Class类对象。
public class DefaultObjectFactory implements ObjectFactory, Serializable {
private static final long serialVersionUID = -8855120656740914948L;
@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
}
@SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> 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(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
Constructor<T> 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 Support
classToCreate = TreeSet.class; // SortedSet类型返回TreeSet对象
} else if (type == Set.class) {
classToCreate = HashSet.class; // Set类型返回HashSet对象
} else {
// 如果不满足以上类型,直接返回原对象
classToCreate = type;
}
return classToCreate;
}
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
② 执行器子包
reflection包下的invoker子包是执行器子包,该子包中的类能够基于反射实现对象方法的调用和对象属性的读写。
Invoker接口
Invoker
接口用于抽象设置和读取字段值的操作。对于有getter/setter
方法的字段,通过MethodInvoker
反射执行;对应其它字段,通过GetFieldInvoker
和SetFieldInvoker
操作Feild
对象的getter/setter
方法反射执行。
public interface Invoker {
// 执行Field或者Method
Object 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();
}
}
@Override
public 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;
}
}
@Override
public 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
*/
@Override
public 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;
}
}
// 获取属性类型
@Override
public 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
*/
@Override
public 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;
}
// 获取属性类型
@Override
public 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{
id=1, name='张三'}
User{
id=1, 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(