文章目录
- 前言
- 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 {@Overridepublic <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> {@Overridepublic 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.xmltype-aliases-package: com.star.mybatis.commonconfiguration:map-underscore-to-camel-case: trueobject-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详解。