ObjectFactory是一个定义了创建新对象的接口,即如其名称得上是一个对象工厂。Mybatis每次在创建Mapper映射结果对象实例的时候,就会使用ObjectFactory来完成对象实例。其接口在Mybatis源代码中只有一个默认的实现,即DefaultObjectFactory。
DefaultObjectFactory实现了ObjectFactory接口定义的所有API。
ObjectFactory objectFactory = new DefaultObjectFactory();
List<String> list = objectFactory.create(List.class);
Robot robot = objectFactory.create(Robot.class);
如上述示例代码所示,使用ObjectFactory来创建对象实例是一件相当轻松的事情,首先通过DefaultObjectFactory的构造方法构造一个ObjectFactory对象,然后调用对应的create方法,就可以创建一个对象实例。
对象实例的创造者
通过示例代码能看出,通过ObjectFactory的create方法能创建对象实例,接下来看看create方法的源代码细则。
@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
}
/**
* @param type 想要创建的对象
* @param constructorArgTypes 构造方法中参数的类型
* @param constructorArgs 构造方法中参数的值
*/
@SuppressWarnings("unchecked")
@Override
public <T> T create(
Class<T> type,
List<Class<?>> constructorArgTypes,
List<Object> constructorArgs) {
// 解析接口类型
Class<?> classToCreate = resolveInterface(type);
// 实例化对象
return (T) instantiateClass(
classToCreate, constructorArgTypes, constructorArgs);
}
源代码中的create方法一共做了两件事,一是解析type对应的接口类型,获取接口对应的实现类,一是通过所传入的构造方法中的constructorArgTypes(类型)和constructorArgs(值)来实例化type对象。
解析接口类型
protected Class<?> resolveInterface(Class<?> type) {
Class<?> classToCreate;
if (type == List.class
|| type == Collection.class
|| type == Iterable.class) {
classToCreate = ArrayList.class;
} else if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) { // issue #510 Collections Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
}
resolveInterface是对象实例化的第一步,源代码显示,如果想要实例化的接口是List或Collection亦或Iterable,那么对应的实现类是ArrayList;如果想要实例化的接口是Map,那么对应的实现类是HashMap;如果想要实例化的接口是SortedSet,那么对应的实现类是TreeSet;如果想要实例化的接口是Set,那么对应的实现类是HashSet。
实例化对象
private <T> T instantiateClass(
Class<T> type,
List<Class<?>> constructorArgTypes,
List<Object> constructorArgs) {
try {
Constructor<T> constructor;
if (constructorArgTypes == null || constructorArgs == 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[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]));
} 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);
}
}
instantiateClass的源代码相对长一点,但是整篇源代码中只做了两件事,一是判断所传入的constructorArgTypes(类型)和constructorArgs(值)是否为空,如果为空,就直接获取对应的构造方法,然后再实例化对象;如果不为空,则先根据constructorArgTypes所传的参数类型获取待实例化对象带参数的构造方法,然后再使用constructorArgs来实例化对象。其余剩下的源代码就是当发现异常时的处理操作。
自定义ObjectFactory
Mybatis之所以在创建Mapper映射结果对象的时候使用ObjectFactory,主要是为了给Mybatis的使用者提供一个扩展机制,以应对使用者在创建对象实例时候的一些特殊逻辑,如将某个业务编码织入到某个特定的对象中。
注:如果通过继承DefaultObjectFactory类的方法来实现了自定义的ObjectFactory,那么就得使用Mybatis提供的标签来注册自定义的ObjectFactory。
<objectFactory type="">
<property name="" value=""/>
</objectFactory>