当我们把数据库返回的结果集转换为实体类的时候,需要创建对象的实例,由于我们不知道需要处理的类型是什么,有哪些属性,所以不能用new 的方式去创建。在MyBatis 里面,它提供了一个工厂类的接口,叫做ObjectFactory,专门用来创建对象的实例,里面定义了4 个方法。
方法 | 作用 |
void setProperties(Properties properties); | 设置参数时调用 |
<T> T create(Class<T> type); | 创建对象(调用无参构造函数) |
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs); | 创建对象(调用带参数构造函数) |
<T> boolean isCollection(Class<T> type) | 判断是否集合 |
ObjectFactory 有一个默认的实现类DefaultObjectFactory,创建对象的方法最终都调用了instantiateClass(),是通过反射来实现的。
如果想要修改对象工厂在初始化实体类的时候的行为,就可以通过创建自己的对象工厂,继承DefaultObjectFactory 来实现(不需要再实现ObjectFactory 接口)。
例如:
public class GPObjectFactory extends DefaultObjectFactory {
@Override
public Object create(Class type) {
if (type.equals(Blog.class)) {
Blog blog = (Blog) super.create(type);
blog.setName("by object factory");
blog.setBid(1111);
blog.setAuthorId(2222);
return blog;
}
Object result = super.create(type);
return result;
}
}
我们可以直接用自定义的工厂类来创建对象:
public class ObjectFactoryTest {
public static void main(String[] args) {
GPObjectFactory factory = new GPObjectFactory();
Blog myBlog = (Blog) factory.create(Blog.class);
System.out.println(myBlog);
}
}
这样我们就直接拿到了一个对象。
如果在config 文件里面注册,在创建对象的时候会被自动调用:
<objectFactory type="org.mybatis.example.GPObjectFactory">
<!-- 对象工厂注入的参数-->
<property name="leon" value="666"/>
</objectFactory>
这样,就可以让MyBatis 的创建实体类的时候使用我们自己的对象工厂。
应用场景举例:
比如有一个新锐手机品牌在一个电商平台上面卖货,为了让预约数量好看一点,只要有人预约,预约数量就自动乘以3。这个时候就可以创建一个ObjectFactory,只要是查询销量,就把它的预约数乘以3 返回这个实体类。
被发现后,平台:是程序员干的。
附:
1、什么时候调用了objectFactory.create()?
创建DefaultResultSetHandler 的时候,和创建对象的时候。
2、创建对象后,已有的属性为什么被覆盖了?
在DefaultResultSetHandler 类的395 行getRowValue()方法里面里面调用了applyPropertyMappings()。
3、返回结果的时候,ObjectFactory 和TypeHandler 哪个先工作?
先是ObjectFactory,再是TypeHandler。肯定是先创建对象。
PS:step out 可以看到一步步调用的层级。