Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)
ObjectFactory官方简介:MyBatis每次创建结果集对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。 默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。 如果想覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。
ObjectFactory接口源码:
public interface ObjectFactory {
/**
* mybatis核心配置文件中自配置<objectFactory><property></property></objectFactory>
* <p>
* 中的property标签的内容,会在加载配置文件后,设置到Properties对象中
*/
void setProperties(Properties properties);
/**
* 根据默认构造创建一个对象示例
*/
<T> T create(Class<T> type);
/**
* 根据有参数构造,创建一个实例,
* type:字节码对象Class
* constructorArgTypes:构造方法中的各个参数类型
* constructorArgs:构造方法中的各个参数值
*/
<T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
/**
* 判断创建对象的字节码Class是否是集合类型
*/
<T> boolean isCollection(Class<T> type);
}
DefaultObjectFactory源码分析:(mybatis提供的ObjectFactory唯一实现)
/**
* @author Clinton Begin
*/
public class DefaultObjectFactory implements ObjectFactory, Serializable { private static final long serialVersionUID = -8855120656740914948L; /**
* 默认构造方法调用有参构造,参数类型和参数都设为null
*/
@Override
public <T> T create(Class<T> type) {
return create(type, null, null);
} @SuppressWarnings("unchecked")
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
/**
* resolveInterface方法根据字节码Class的类型返回该类型的一个具象化实例Class
*/
Class<?> classToCreate = resolveInterface(type);
// 类型是可以赋值的,返回一个初始化的实例对象
return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
} @Override
public 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();
}
/**
* 有参构造时,根据字节码Class和参数类型列表constructorArgTypes反射获取到有参数的构造方法Constructor
*/
constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
if (!constructor.isAccessible()) {
//如果构造方法是私有的,则设置可被访问到
constructor.setAccessible(true);
}
//最后用获得的构造方法对象constructor和参数列表constructorArgs反射获取到实例对象返回
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 Support
classToCreate = TreeSet.class;
} else if (type == Set.class) {
classToCreate = HashSet.class;
} else {
classToCreate = type;
}
return classToCreate;
} /**
* 字节码Class是否是一个Collection
*/
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
说明:默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。它不做其他任何的处理。如果我们想在创建实例化一个目标类的时候做点啥其他的动作,可以继承DefaultObjectFactory,覆写父类方法,并在mybatis-config.xml中注册配置这个对象工厂类。
认知(知识有限,全靠想象,希望看官指正):
ObjectFactory在Mybatis中的一个用处:
我认为当在mapper文件中指定一条sql映射时,返回值类型就是用ObjectFactory要去创建的实例,并且sql查询出的结果集被解析为ObjectFactory创建实例需要的参数类型列表和参数列表
Mybatis框架基础支持层——反射工具箱之对象工厂ObjectFactory&DefaultObjectFactory(5)的更多相关文章
- Mybatis框架基础支持层——反射工具箱之Reflector&ReflectorFactory(3)
说明:Reflector是Mybatis反射工具的基础,每个Reflector对应一个类,在Reflector中封装有该类的元信息, 以及基于类信息的一系列反射应用封装API public class ...
- Mybatis框架基础支持层——反射工具箱之实体属性Property工具集(6)
本篇主要介绍mybatis反射工具中用到的三个属性工具类:PropertyTokenizer.PropertyNamer.PropertyCopier. PropertyTokenizer: 主要用来 ...
- Mybatis框架基础支持层——反射工具箱之MetaClass(7)
简介:MetaClass是Mybatis对类级别的元信息的封装和处理,通过与属性工具类的结合, 实现了对复杂表达式的解析,实现了获取指定描述信息的功能 public class MetaClass { ...
- Mybatis框架基础支持层——反射工具箱之泛型解析工具TypeParameterResolver(4)
简介:TypeParameterResolver是一个工具类,提供一系列的静态方法,去解析类中的字段.方法返回值.方法参数的类型. 在正式介绍TypeParameterResolver之前,先介绍一个 ...
- Mybatis框架基础支持层——日志模块(8)
前言: java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同.为了统一这些工具的接 ...
- Mybatis框架基础支持层——解析器模块(2)
解析器模块,核心类XPathParser /** * 封装了用于xml解析的类XPath.Document和EntityResolver */ public class XPathParser { / ...
- MyBatis源码分析-基础支持层反射模块Reflector/ReflectorFactory
本文主要介绍MyBatis的反射模块是如何实现的. MyBatis 反射的核心类Reflector,下面我先说明它的构造函数和成员变量.具体方法下面详解. org.apache.ibatis.refl ...
- 精尽 MyBatis 源码分析 - 基础支持层
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis 框架 基础应用
1.ORM的概念和优势 概念: 对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据 ...
随机推荐
- python 可迭代对象 迭代器 生成器总结
可迭代对象 只要有魔法方法__iter__的就是可迭代对象 list和tuple和dict都是可迭代对象 迭代器 只要有魔法方法__iter__和__next__的就是可迭代对象 生成器 只要含有y ...
- windows下 mysql 5.6.40 卸载 安装 修改密码
最近执行另一个mysql版本导出的sql脚本,出现问题!出于一些原因,把之前的mysql5.5卸载,由于卸载不干净出现了一些问题.特此总结方法! 参考链接: https://blog.csdn.net ...
- MVC编程模型
MVC 编程模型 MVC 是三个 ASP.NET 开发模型之一. MVC 是用于构建 web 应用程序的一种框架,使用 MVC (Model View Controller) 设计: Model(模型 ...
- 《JavaScript DOM编程艺术》学习笔记(一)
这本书是我听说学习前端基础入门书籍,于是就开始看了,大概是从5月10号开始看的吧,一直看到现在,差不多要看完了,书是挺厚的...286页,不过比起JAVASCRIPT权威指南来说还是差多了,权威指南才 ...
- FCC(ES6写法) Friendly Date Ranges
把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式. 易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1). 包含当前年份和相同月份的时候,makeFri ...
- LeetCode编程训练 - 回溯(Backtracking)
回溯基础 先看一个使用回溯方法求集合子集的例子(78. Subsets),以下代码基本说明了回溯使用的基本框架: //78. Subsets class Solution { private: voi ...
- emWin监护仪界面设计,含uCOS-III和FreeRTOS两个版本
第5期:监护仪界面设计 配套例子:V6-908_STemWin提高篇实验_监护仪界面设计(uCOS-III)V6-909_STemWin提高篇实验_监护仪界面设计(FreeRTOS) 例程下载地址:h ...
- [Swift]LeetCode221. 最大正方形 | Maximal Square
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and re ...
- [Swift]LeetCode701. 二叉搜索树中的插入操作 | Insert into a Binary Search Tree
Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert t ...
- oracle 合并多个sys_refcursor
一.背景 在数据开发中,有时你需要合并两个动态游标sys_refcursor. 开发一个存储过程PROC_A,这个过程业务逻辑相当复杂,代码篇幅较长.一段时间后要开发一个PROC_B,要用PROC_A ...