文章目录
上篇文章 Mybatis系列(六)typeHandler源码解析,对mybatis的类型转换器有了简单的认识,除了我们使用默认提供的typeHandler之外,在平时的项目中,也经常用到自定义的枚举typeHandler,今天这节我们来看看mybatis的对象工厂(objectFactory)是怎么一回事。
依旧从XMLConfigBuilder解析xml配置文件中的objectFactory节点看起
一、objectFactoryElement源码
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
//type属性,获取type节点指定对应的对象工厂
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
//创建ObjectFactory,依旧是创建别名的这个方法resolveClass
ObjectFactory factory = (ObjectFactory)this.resolveClass(type).newInstance();
factory.setProperties(properties);
//放入configuration,备用
this.configuration.setObjectFactory(factory);
}
}
ObjectFactory 接口
public interface ObjectFactory {
void setProperties(Properties var1);
<T> T create(Class<T> var1);
<T> T create(Class<T> var1, List<Class<?>> var2, List<Object> var3);
<T> boolean isCollection(Class<T> var1);
}
从接口的定义看,接口有两个通过反射实现得构造函数,另外,为了使的这个工厂类能接收设置的附带属性,还提供了setProperties()
方法。
当创建结果集时,mybatis会使用一个对象工厂来完成创建这个结果集实例。在默认的情况下,mybatis会使用其定义的对象工厂——DefaultObjectFactory
来完成相应的工作,有兴趣的可以看一下源码的实现类,其实它创建实例对象最终都是通过instantiateClass()
方法能实现的,下边会讲到。
ObjectFactory是不是很简单,看到这里可能会问前两节讲的typeAliases
和typeHandler
,mybatis都提供了默认的配置,并且支持自定义的typeAliases
和typeHandler
,那么ObjectFactory是否也支持自定义呢?答案是肯定的。下边我们就创建一个自定义的ObjectFactory
——MyObjectFactory
。
二、自定义ObjectFactory
如果自定义需要实现接口ObjectFactory
,并给予配置。在大部分情况下,我们不需要自定义返回规则,因为这些比较复杂容易出错,在更多情况下,都会考虑系统已经实现的DefaultObjectFactory
,通过继承它来完成我们需要的工作。
public class MyObjectFactory extends DefaultObjectFactory {
private static final long serialVersionUID = -7924251036323382165L;
Logger logger = Logger.getLogger(MyObjectFactory.class);
private Object temp = null;
public void setProperties(Properties properties) {
super.setProperties(properties);
logger.info("初始化参数:--------"+properties.toString());
}
//方法2
public <T> T create(Class<T> type) {
T result = super.create(type);
logger.info("创建对象:--------"+result.toString());
logger.info("是否和上次创建的是同一个对象:【"+temp.equals(result) +"】");
return result;
}
//方法1
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
T result = super.create(type, constructorArgTypes, constructorArgs);
logger.info("创建对象:--------"+result.toString());
temp = result;
return result;
}
public <T> boolean isCollection(Class<T> type) {
return super.isCollection(type);
}
}
三、objectFactory在mybatis-config.xml的配置
<objectFactory type="com.sean.factory.MyObjectFactory">
<property name="prop1" value="value1"/>
</objectFactory>
这样mybatis就会采用配置的MyObjectFactory
来生成结果集对象,我们测试一下:
四、自定义objectFactory测试
测试代码,依旧是前几节用过的findUserById
public void findUserByIdTest(){
SqlSession sqlSession = getSessionFactory().openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(1L);
logger.debug(user.getName());
}
日志打印:
如果打断点调试,会发现mybatis创建了一个List对象和一个User对象,它会先调用方法1,然后调用方法2,只是最后生成了同一个对象,所以在写入的判断中,始终返回的是true,因为返回的是同一个User对象,所以它会最后适配为一个User对象,这就是它的工作过程。
为什么会创建一个List对象和一个类对象?请看这个方法
resolveInterface
protected Class<?> resolveInterface(Class<?> type) {
Class classToCreate;
//判读是否集合,比如我们传入User,那么就直接返回类对象
if (type != List.class && type != Collection.class && type != Iterable.class) {
if (type == Map.class) {
classToCreate = HashMap.class;
} else if (type == SortedSet.class) {
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
//直接返回对象
classToCreate = type;
}
} else {
//直接返回List对象
classToCreate = ArrayList.class;
}
return classToCreate;
}
objectFactory节点就讲到这里,平时开发中,用到的也比较少,大致了解下怎么回事即可。