文章目录
- 前言
- 3.6 ObjectFactory
- 3.7 ProxyFactory
- 3.8 小结
前言
本节研究ObjectFactory和ProxyFactory的基本用法,因为它们在MyBatis的源码中比较常见。这里不深究ObjectFactory和ProxyFactory的源码,而是放到后续章节再展开。
3.6 ObjectFactory
ObjectFactory是MyBatis中的对象工厂,主要作用是实例化目标类。它只有一个默认的实现,即DefaultObjectFactory。
MyBatis在每次创建Mapper映射结果对象的新实例时,均会使用ObjectFactory对象工厂来完成。
下面是使用ObjectFactory创建新对象的示例:
@Test
public void testObjectFactory() {
ObjectFactory objectFactory = new DefaultObjectFactory();
Order order = objectFactory.create(Order.class);
order.setOrderNo("NO.1986");
order.setGoodsName("《西游记》");
System.out.println(order.toString());
}
控制台输出执行结果:
Order{orderNo='NO.1986', goodsName='《西游记》'}
需要注意的是,ObjectFactory支持通过接口的方式创建对象,例如指定要创建java.util.List
的实例时,实际上会创建java.util.ArrayList
对象。List、Map、Set接口对应的实现分别是ArrayList、HashMap、HashSet。
ObjectFactory实际上是MyBatis的一种扩展机制。某些情况下,在得到Mapper映射结果之前需要处理一些额外的逻辑,或者在执行该类的有参构造方法之前,要对参数进行一些处理,则可以通过自定义的ObjectFactory来实现。
下面通过一个简单的SpringBoot整合MyBatis项目,演示自定义的ObjectFactory如何影响目标对象的创建:
(1)在pom.xml中导入SpringBoot和MyBatis的依赖
(2)创建自定义ObjectFactory:需要继承DefaultObjectFactory类并重写create()
方法
public class UserObjectFactory extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type) {
System.out.println("自定义UserObjectFactory执行了...");
return super.create(type);
}
}
(3)创建ObjectFactory转换器:程序读取到UserObjectFactory类后会使用该转换器将其转换为ObjectFactory类
@Component
@ConfigurationPropertiesBinding
public class ObjectFactoryConverter implements Converter<String, ObjectFactory> {
@Override
public ObjectFactory convert(String s) {
try {
return (ObjectFactory) Class.forName(s).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
(4)创建Mapper接口与xml文件
@Mapper
public interface UserMapper {
public List<User> selectAll();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.star.mybatis.test11.UserMapper">
<select id="selectAll" resultType="User">
SELECT * FROM USER
</select>
</mapper>
(5)在application.properties配置文件中配置MyBatis
# datasource等配置省略...
mybatis:
mapper-locations: classpath*:/mapper/**Mapper.xml
type-aliases-package: com.star.mybatis.common
configuration:
map-underscore-to-camel-case: true
object-factory: com.star.mybatis.test11.UserObjectFactory
(6)编写主启动类
@SpringBootApplication
public class CustomObjectFactoryApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(CustomObjectFactoryApp.class, args);
UserMapper userMapper = (UserMapper) context.getBean("userMapper");
List<User> userList = userMapper.selectAll();
userList.forEach(System.out::println);
}
}
(7)执行主启动类,得到结果
执行创建User对象的自定义逻辑...
执行创建User对象的自定义逻辑...
User{id=1, name='孙悟空', age=18, phone='18705464523', birthday=Mon Feb 21 10:24:30 CST 2000}
User{id=22, name='user1', age=18, phone='18705464523', birthday=Mon Feb 21 10:24:30 CST 2000}
由执行结果可知,在得到映射结果对象之前执行了自定义的ObjectFactory,那就可以在这个自定义的ObjectFactory中做一些额外的处理。
3.7 ProxyFactory
ProxyFactory是MyBatis中的代理工厂,用于创建动态代理对象。
ProxyFactory接口有两个不同的实现,分别为CglibProxyFactory和JavassistProxyFactory。从实现类的名称就可知道,MyBatis支持两种动态代理策略,分别是Cglib和Javassist动态代理。
ProxyFactory主要用于实现MyBatis的懒加载功能。当开启懒加载后,懒加载创建Mapper映射结果对象后,会通过ProxyFactory创建映射结果对象的代理对象。当调用代理对象的getter方法获取数据时,会执行CglibProxyFactory或JavassistProxyFactory中定义的拦截逻辑。
关于懒加载的细节,放到后面的章节再研究,本节主要了解ProxyFactory的使用。
下面是一个ProxyFactory的使用示例:
@Test
public void testProxyFactory() {
// 创建ProxyFactory对象
ProxyFactory proxyFactory = new JavassistProxyFactory();
Order order = new Order("NO.1986", "《西游记》");
// 调用ProxyFactory对象的createProxy方法
Object proxy = proxyFactory.createProxy(order,
new ResultLoaderMap(),
new Configuration(),
new DefaultObjectFactory(),
Arrays.asList(String.class, String.class),
Arrays.asList(order.getOrderNo(), order.getGoodsName()));
System.out.println(proxy.getClass());
System.out.println(((Order)proxy).getOrderNo());
System.out.println(((Order)proxy).getGoodsName());
}
控制台输出执行结果:
class com.star.mybatis.common.Order_$$_jvst3c2_0
NO.1986
《西游记》
在示例中,创建了一个Order对象,然后通过JavassistProxyFactory实例创建了一个Order对象的动态代理对象。
动态代理对象创建完毕后,会把原始对象的属性复制到代理对象中。
3.8 小结
第三章到此就梳理完毕了,本章的主题是:MyBatis常用工具类。回顾一下本章的梳理的内容:
(八)SQL工具类
(九)ScriptRunner&SqlRunner
(十)MetaObject&MetaClass
(十一)ObjectFactory&ProxyFactory
这些工具类在MyBatis源码中出现的频率较高,了解这些工具类的使用及实现原理有助于深入研究MyBatis的源码。
- SQL工具类用于在Java代码中动态构建SQL语句;
- SqlRunner和ScriptRunner用于执行SQL脚本和SQL语句;
- MetaObject和MetaClass是MyBatis中的反射工具类,封装了对类和对象的操作;
- ObjectFactory和ProxyFactory是对象创建相关的工具类,ObjectFactory用于创建Mapper映射实体对象,而ProxyFactory则用于创建Mapper 映射实体对象的动态代理对象,通过动态代理来实现MyBatis 中的懒加载机制。
更多内容请查阅分类专栏:MyBatis3源码深度解析
第四章主要学习:MyBatis核心组件。主要内容包括:
- 使用MyBatis操作数据库;
- MyBatis核心组件;
- Configuration详解;
- Executor详解;
- MappedStatement详解;
- StatementHandler详解;
- TypeHandler详解;
- ParameterHander详解;
- ResultSetHandler详解。