Mybatis 源码学习-反射工具(ObjectFactory)
Posted 凉茶方便面
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis 源码学习-反射工具(ObjectFactory)相关的知识,希望对你有一定的参考价值。
历史文章:
Mybatis 源码学习(3)-反射工具(TypeParameterResolver)
ObjectFactory 相对简单,它是一个接口,定义了如何创建 Mybatis 中的对象,在 Mybatis 的配置文件中,可以直接自定义 ObjectFactory 的接口实现类。Mybatis 默认提供了 ObjectFactory 的实现类:DefaultObjectFactory。
ObjectFactory 的接口定义
ObjectFactory 接口的定义比较简单,它提供了 create 方法用于创建对象,允许传入无构造方法的类以及多个构造方法的类。
public interface ObjectFactory
// 设置外部配置信息
void setProperties(Properties properties);
// 通过无参数的构造器创建指定对象
<T> T create(Class<T> type);
// 根据参数列表,从指定的 class 中创建对象
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
// 检测指定类型是否为集合类型,主要处理 java.util.Collection 及其子类
<T> boolean isCollection(Class<T> type);
实现类 DefaultObjectFactory
DefaultObjectFactory 是 ObjectFactory 的唯一实现,它提供了通过反射创建对象的方法。它有两个 create 方法,分别用来创建无参构造函数和有参构造函数,内部的创建方法都依赖 instantiateClass(type, constructorArgTypes, constructorArgs) 方法的实现。
public class DefaultObjectFactory implements ObjectFactory, Serializable
// 两个 create 方法的实现
public <T> T create(Class<T> type)
return create(type, null, null);
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs)
Class<?> classToCreate = resolveInterface(type);
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
// 默认实现不使用外部 Properties
public void setProperties(Properties properties)
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(); // 获取无参构造函数
if (!constructor.isAccessible())
constructor.setAccessible(true);
return constructor.newInstance();
// 根据参数列表获取对应的构造函数
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible())
constructor.setAccessible(true);
// 将参数代入,构造对象
return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
catch (Exception e)
// 构造逗号分割的参数类型列表
StringBuilder argTypes = new StringBuilder();
if (constructorArgTypes != null && !constructorArgTypes.isEmpty())
for (Class<?> argType : constructorArgTypes)
argTypes.append(argType.getSimpleName());
argTypes.append(",");
argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
// 构造逗号分割的参数列表
StringBuilder argValues = new StringBuilder();
if (constructorArgs != null && !constructorArgs.isEmpty())
for (Object argValue : constructorArgs)
argValues.append(String.valueOf(argValue));
argValues.append(",");
argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
// 返回错误日志
throw new ReflectionException(“…”);
// 将集合类型转化为实际的具体实现类
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;
// 仅仅检查是否是 Collection 的子类
public <T> boolean isCollection(Class<T> type)
return Collection.class.isAssignableFrom(type);
总结
ObjectFactory 的方法非常简单,主要定义了如何创建对象、如何判读集合对象,Mybatis 中的所有对象都应该由 ObjectFactory 的实现类创建, 它只提供了 DefaultObjectFactory 作为默认实现,并且允许通过 mybatis-config.xml 配置实现自定义配置。
参考文档:《Mybatis 技术内幕》
本文的基本脉络参考自《Mybatis 技术内幕》,编写文章的原因是希望能够系统地学习 Mybatis 的源码,但是如果仅阅读源码或者仅从官方文档很难去系统地学习,因此希望参考现成的文档,按照文章的脉络逐步学习。
欢迎关注我的公众号:我的搬砖日记,我会定时分享自己的学习历程。
以上是关于Mybatis 源码学习-反射工具(ObjectFactory)的主要内容,如果未能解决你的问题,请参考以下文章
Mybatis 源码学习-反射工具(TypeParameterResolver)
Mybatis 源码学习-反射工具(ObjectWrapper & MetaObject)