在上篇文章中,我们对<typeHandlers>配置及背后的源码进行了比较详细的说明,今天,我们来对下一个元素<objectFactory>进行详细说明。

这个元素,大家在使用mybatis的时候设置吗?我是从来没有设置过啊。使用mybatis为我们已经写好的默认实现已经能够满足绝大多数的场景需求。那么这个元素又是干什么的呢?

官方文档上是这么说的:

MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。

我理解的意思就是说,这个类其实是为了在对查询结果集中获取数据被封装成所希望的Java实体类型时用到的,使用这个工厂类通过反射的方式来进行实例对象的创建。所有的工厂类都必须实现ObjectFactory接口。我们来看看这个接口的定义:

public interface ObjectFactory {/*** Sets configuration properties.* @param properties configuration properties*/void setProperties(Properties properties);/*** Creates a new object with default constructor. * @param type Object type* @return*/<T> T create(Class<T> type);/*** Creates a new object with the specified constructor and params.* @param type Object type* @param constructorArgTypes Constructor argument types* @param constructorArgs Constructor argument values* @return*/<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);/*** Returns true if this object can have a set of other objects.* It's main purpose is to support non-java.util.Collection objects like Scala collections.* * @param type Object type* @return whether it is a collection or not* @since 3.1.0*/<T> boolean isCollection(Class<T> type);}

从这个接口定义可以看出,它包含了两种通过反射机制构造实体类对象的方法,一种是通过无参构造函数,一种是通过带参数的构造函数。另外,为了使的这个工厂类能接收设置的附带属性,还提供了setProperties()方法。mybatis为我们实现了一个默认实现,那就是DefaultObjectFactory,我们来看看默认是怎么实现的。

public class DefaultObjectFactory implements ObjectFactory, Serializable {private static final long serialVersionUID = -8855120656740914948L;@Overridepublic <T> T create(Class<T> type) {return create(type, null, null);}@SuppressWarnings("unchecked")@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {Class<?> classToCreate = resolveInterface(type);// we know types are assignablereturn (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);}@Overridepublic void setProperties(Properties properties) {// no props for default}<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("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);}}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 SupportclassToCreate = TreeSet.class;} else if (type == Set.class) {classToCreate = HashSet.class;} else {classToCreate = type;}return classToCreate;}@Overridepublic <T> boolean isCollection(Class<T> type) {return Collection.class.isAssignableFrom(type);}}

从上面的源码来看,创建实例对象最终都是通过instantiateClass()方法能实现的,在这个方法中,获取实体类的无参构造函数或者带参构造函数,然后采用反射的机制来实例化实体类对象出来。

如果我们想定义一个自定义的对象工厂类,我们可以实现ObjectFactory这个接口,但是这样我们就需要自己去实现一些在DefaultObjectFactory已经实现好了的东西,因此如果想自定义一个,可以继承这个DefaultObjectFactory类,这样可以使得实现起来更为简单。

下面我们来举个示例,我们假设需要自定义一个对象工厂类ExampleObjectFactory,在要创建我之前定义的User对象时会给属性字段author赋值为我的名字,接下来我们看看怎么实现。

首先我们定义实现这个对象工厂类:

package com.majing.learning.mybatis.reflect.objectfactory;import org.apache.ibatis.reflection.factory.DefaultObjectFactory;import com.majing.learning.mybatis.entity.User;public class ExampleObjectFactory extends DefaultObjectFactory{private static final long serialVersionUID = 3608715667301891724L;@Overridepublic <T> T create(Class<T> type) {T result = super.create(type);if(type.equals(User.class)){((User)result).setAuthor("马靖");}return result;}}

在这个工厂类中,我们对User类中无惨构造函数构造出来的对象做了个特殊处理,加了个我的名字。接下来,我们在配置文件中配置这个类为我们想要的对象工厂类。

<objectFactory type="com.majing.learning.mybatis.reflect.objectfactory.ExampleObjectFactory"></objectFactory>

然后我们执行测试代码,查询一条用户记录出来,发现返回的对象中的确设置了我的名字,如下所示:

至此,关于mybatis中的对象工厂相关的知识点便讲解的差不多了,下一篇文章我们再来看看<Mappers>的配置和使用,敬请期待。

如果想了解我最新的博文,请关注我的博客,谢谢。如果想看到更多相关技术文章并愿意支持我继续写下去,欢迎给我打赏,对您的打赏我表示感谢。

Mybatis配置之objectFactory元素详述相关推荐

  1. MyBatis配置错误

    MyBatis配置错误 "C:\Program Files\Java\jdk1.8.0_144\bin\java" -ea -Didea.test.cyclic.buffer.si ...

  2. mybatis 配置详解

    mybatis 配置详解 mybatis-config.xml 核心配置文件 mybatis-config.xml 包含的内容如下 configuration(配置) properties(属性) s ...

  3. mybatis配置文件属性的详解和db.propertis文件的使用

    Mybatis核心配置文件SqlMapConfig.xml配置 核心配置文件中标签的顺序如下图所示: 1.properties(属性): 将核心配置文件的某些属性(连接池的四大基本属性),可以在外部的 ...

  4. Mybatis配置信息浅析 MyBatis简介(二)

    官方文档入门篇中有明确说明 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的. SqlSessionFactory 的实例可以通过 SqlSessionF ...

  5. 什么是Mybatis配置解析?(源码+图文)

    什么是Mybatis配置解析?(源码+图文) 1. 核心配置文件 mybatis-config.xml configuration(配置)properties(属性)settings(设置)typeA ...

  6. Java-Mybatis(二): Mybatis配置解析、resultMap结果集映射、日志、分页、注解开发、Mybatis执行流程分析

    Java-Mybatis-02 学习视频:B站 狂神说Java – https://www.bilibili.com/video/BV1NE411Q7Nx 学习资料:mybatis 参考文档 – ht ...

  7. mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明

    记录一个发现的小问题,刚刚在UserMapper.xml文件中有一段中文注释掉的内容: <!-- <resultMap id="Usermap" type=" ...

  8. springboot下使用mybatis配置

    springboot下使用mybatis配置 1. 依赖安装 pom.xml文件 <dependency><groupId>org.mybatis.spring.boot< ...

  9. Spring Boot——MyBatis配置带下划线命名的字段自动转换驼峰命名解决方案

    问题描述 MyBatis无法查询出属性名和数据库字段名不完全相同的数据. 即:属性名和数据库字段名分别为驼峰命名和下划线命名时查出的数据为NULL. 问题分析 MyBatis默认是属性名和数据库字段名 ...

最新文章

  1. BTC 缓步推升,BCH 再拔头筹
  2. Spring 初识Aop JDK动态代理实现 原理初显
  3. 如何在 Windows Server 中配置权威时间服务器
  4. 获取数据 - 将Excel文件读入矩阵matrix中 - Python代码
  5. 程序员败给了一个厨子,读书无用论让我 必须送书了
  6. 高颜值在线绘图平台ImageGP系列教程 - 功能介绍
  7. 深入浅出 CAS,很多想进阿里的倒在了这个知识点
  8. Jmeter (三十)jmeter+ant+jenkins持续集成
  9. sql 获取当前日期的季度,年份,月份等日期部分
  10. linux控制主机风扇转速,怎么调整cpu风扇转速 cpu风扇转速调整方法【详解】
  11. html页面设计扁平化,35个扁平化网站设计灵感
  12. 十大深网搜索引擎,它们提供了你无法从Google和Bing获取的信息
  13. R、冗余分析(RDA)、ggplot2、置信椭圆
  14. imprinted weights
  15. java实现打字母小游戏
  16. 感恩节(11.28)
  17. px4+ros+gazebo+ORB_SLAM2室内视觉无人机导航
  18. eclipese web前端开发教学_Web 前端怎样入门?
  19. Debian Linux 的安装
  20. 中文 latex 排版没有斜体

热门文章

  1. linux原生迅雷文本模式,ubuntu 下运行原生的迅雷
  2. 智能座舱语音交互自动化测试
  3. NOI 44:第n小的质数(C++)
  4. 人脸识别+移动考勤,这个组合很厉害
  5. ln, lg, log在C中的应用
  6. win10密码忘了怎么办_vivo S7忘了手机密码怎么办?手机怎么解锁?
  7. notepad如何新建php,notepad怎样使用教程
  8. 最早walkman android,入手一年,聊聊索尼 ZX505、艾利和SR15 两款安卓播放器使用体验...
  9. 哈佛最年轻华人正教授尹希:中国教育问题在埋没太多天赋,少年班给了更多选择来弥补教育短板(公号回复“哈佛尹希”下载PDF资料)
  10. 【iOS知识学习】_iPhone清理缓存