文章目录
- 前言
 - 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详解。
 


















