Mybatis常用工具类(四)-- ObjectFactory、ProxyFactory

iBit程序猿 2020年06月17日 1,618次浏览

ObjectFactory

每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。 ObjectFactory 的默认实现为 DefaultObjectFactory。默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认无参构造方法,要么通过存在的参数映射来调用带有参数的构造方法。

ObjectFactory 方法

方法说明
create(type)处理无参构造方法
create(type, constructorArgTypes, constructorArgs)处理有参构造方法
setProperties(properties)设置配置属性
isCollection(type)判断是否为集合类型

ObjectFactory 接口很简单,它包含两个创建实例用的方法,一个是处理默认无参构造方法的,另外一个是处理带参数的构造方法的。

默认无参构造方法示例:

ObjectFactory objectFactory = new DefaultObjectFactory();
Person person = objectFactory.create(Person.class);

带参数的构造方法示例:

ObjectFactory objectFactory = new DefaultObjectFactory();
Person person = objectFactory.create(Person.class,
        Arrays.asList(Integer.class, String.class, String.class),
        Arrays.asList(1, "小ben马", "小ben马"));

如果想覆盖对象工厂的默认行为,可以通过创建自己的对象工厂来实现。eg:

public class PersonObjectFactory extends DefaultObjectFactory {
    
    // 定义额外属性
    private Properties properties;

    @Override
    public Object create(Class type) {
        if (type.equals(Person.class)) {
            Person person = (Person) super.create(type);
            person.setNickName(UUID.randomUUID().toString());
            return person;
        }
        return super.create(type);
    }

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
<!-- mybatis-config.xml -->
<objectFactory type="tech.ibit.mybatis.learning.common.tools.factory.PersonObjectFactory">
  <!--设置其他属性-->
  <property name="someProperty" value="100"/>
</objectFactory>

另外,setProperties 方法可以被用来配置 ObjectFactory,在初始化你的 ObjectFactory 实例后, objectFactory 元素体中定义的属性会被传递给 setProperties 方法。

ProxyFactory

ProxyFactory 是 Mybatis 中的代理工厂,主要用于动态代理对象。 ProxyFactory 两个实现,JavassistProxyFactory(支持Javassist动态代理) 和 CglibProxyFactory(支持Cglib动态代理)。ProxyFactory 主要用于 Mybatis 的懒加载功能。当开启懒加载后,Mybatis 创建 Mapper 映射结果对象后,会通过 ProxyFactory 创建映射结果对象的代理对象。当我们调用代理对象的 Getter 方法获取数据时,会执行 JavassistProxyFactory 或 CglibProxyFactory 中定义的拦截逻辑,然后执行一次额外的查询。

ProxyFactory 主要方法

方法说明
createProxy(target, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs)创建代理

示例代码

JavassistProxyFactory示例

// 创建ProxyFactory对象
ProxyFactory proxyFactory = new JavassistProxyFactory();
Person person = new Person(1, "小ben马", "小ben马");
ObjectFactory objectFactory = new DefaultObjectFactory();

// 调用ProxyFactory对象的createProxy()方法创建代理对象
Object proxyOrder = proxyFactory.createProxy(
        person,
        new ResultLoaderMap(),
        new Configuration(),
        objectFactory,
        Arrays.asList(Integer.class, String.class, String.class),
        Arrays.asList(person.getPersonId(), person.getPersonName(), person.getNickName())
);
System.out.println(proxyOrder.getClass());
System.out.println(((Person) proxyOrder).getPersonName());

输出结果>>>

class tech.ibit.mybatis.learning.common.tools.entity.Person_$$_jvst5_0
小ben马

CglibProxyFactory示例

// 创建ProxyFactory对象
ProxyFactory proxyFactory = new CglibProxyFactory();
Person person = new Person(1, "小ben马", "小ben马");
ObjectFactory objectFactory = new DefaultObjectFactory();

// 调用ProxyFactory对象的createProxy()方法创建代理对象
Object proxyOrder = proxyFactory.createProxy(
        person,
        new ResultLoaderMap(),
        new Configuration(),
        objectFactory,
        Arrays.asList(Integer.class, String.class, String.class),
        Arrays.asList(person.getPersonId(), person.getPersonName(), person.getNickName())
);
System.out.println(proxyOrder.getClass());
System.out.println(((Person) proxyOrder).getPersonName());

需要引入 cglib 相关依赖包。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

输出结果>>>

class tech.ibit.mybatis.learning.common.tools.entity.Person$$EnhancerByCGLIB$$bfe52ae9
小ben马