聊聊 mybatis 的反射之对象工厂
今天的这篇文章会给大家讲解一下 Mybatis 的反射模块的一个重要的概念,那就是对象工厂。
ObjectFactory 是对象工厂接口,mybatis 可以使用 ObjectFactory 创新需要的新的对象,默认实现类是 DefaultObjectFactory,这个类主要是实现 ObjectFactory 接口的 create 方法,
DefaultObjectFactory 默认对象工厂类
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 构造方法入参
* @param <T> 实例类型
* @return 创建的实例
*/
private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
try {
// 构造方法
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == null) { // 参数类型列表为null或者参数列表为null
// 因此获取无参构造函数
constructor = type.getDeclaredConstructor();
try {
// 使用无参构造函数创建对象
return constructor.newInstance();
} catch (IllegalAccessException e) {
// 如果发生异常,则修改构造函数的访问属性后再次尝试
if (Reflector.canControlMemberAccessible()) {
constructor.setAccessible(true);
return constructor.newInstance();
} else {
throw e;
}
}
}
// 根据入参类型查找对应的构造器
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
try {
// 采用有参构造函数创建实例
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} catch (IllegalAccessException e) {
if (Reflector.canControlMemberAccessible()) {
// 如果发生异常,则修改构造函数的访问属性后再次尝试
constructor.setAccessible(true);
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
} else {
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);
}
}
复制代码
这一块的代码注释也非常详细,通过源码我们能看到,create()方法调用 instantiateClass()方法来创建类实例,具体过程就是根据传入的参数选择不同的构造方法来进行实例化对象,如果没有传入参数就使用无参构造器,传入了参数就使用有参构造器
property 包
property 文件夹有三个类:PropertyCopier,PropertyNamer 和 PropertyTokenizer
PropertyCopier
PropertyCopier 是一个工具类,主要是属性的复制,核心方法 copyBeanProperties(),完成对象的输出拷贝功能
PropertyNamer
PropertyNamer 类是属性名称的处理器,它的主要功能是把方法名转换为属性名,还有判断这个方法是不是 getter 或 setter 方法,
PropertyTokenizer
PropertyTokenizer 是用来属性解析的,比如传入 student[index].name,它能解析出 student,index,student[index],name
总结
这篇文章主要介绍了 ObjectFactory 对象工厂接口和它的实现类 DefaultObjectFactory,功能就是根据参数调用适合的构造器生成对象,主要分析了 DefaultObjectFactory 的 create()方法的实现,然后介绍了一下 property 文件夹下的三个类:PropertyCopier 是用来进行属性复制的工具类,PropertyNamer 是属性名称处理器,主要实现将方法名转为属性名,PropertyTokenizer 是属性的解析类,这些工具我们在生产的时候也经常会遇到对象属性拷贝的情景,我们可以参考这些类的实现解决这些情景。
评论