Mybatis标签之 objectFactory 使用及解析

Mybatis标签之 objectFactory 使用及解析

一、ObjectFactory的作用

当我们把数据库返回的结果集转换为实体类的时候,需要创建对象的实例,由于我 们不知道需要处理的类型是什么,有哪些属性,所以不能用 new 的方式去创建。在 MyBatis 里面,它提供了一个工厂类的接口,叫做 ObjectFactory,专门用来创建对象的实例。

二、自定义 ObjectFactory

创建一个用于示例的Blog 实体类:

/**
 * @Description: Blog 实体类
 * @Author zdp
 * @Date 2021-12-07 16:33
 */
@Data
public class Blog implements Serializable{
    
    private static final long serialVersionUID = 7145310512414135264L;
    
    /**
     * 博客ID
     */
    private Integer bid;
    /**
     * 博客标题
     */
    private String name;
    /**
     * 博客作者ID
     */
    private Integer authorId;

}

1. 编写自定义CustomObjectFactory

/**
 * @Description: CustomObjectFactory
 * @Author zdp
 * @Date 2021-12-09 16:57
 * <p>
 * 自定义ObjectFactory,通过反射的方式实例化对象 一种是无参构造函数,一种是有参构造函数
 */
public class CustomObjectFactory extends DefaultObjectFactory {

    /**
     * 当要创建的实体类类型为Blog时,使用我们自己创建的Blog对象,并且需要做一些前置的业务操作
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T create(Class<T> type) {
        if (type.equals(Blog.class)) {
            System.out.println("前置业务操作....");
            Blog blog = new Blog();
            blog.setBid(888);
            blog.setName("custom objectFactory..");
            blog.setAuthorId(888);
            return (T)blog;
        }
        return super.create(type);
    }

    @Override
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
    }

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);
    }

    @Override
    public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
    }

}

2. 在mybatis-config.xml 文件中注册自定义的CustomObjectFactory

    <!-- 对象工厂 -->
    <objectFactory type="com.zdp.objectfactory.CustomObjectFactory">
        <property name="CustomObjectFactory" value="123"/>
    </objectFactory>

3. 编写一个查询Blog的测试方法

    @Test
    public void testQueryBlog() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession session = sqlSessionFactory.openSession();
        try {
            BlogMapper mapper = session.getMapper(BlogMapper.class);
            Blog blog = mapper.selectBlogById(1);
            System.out.println(blog);
        } finally {
            session.close();
        }
    }

4. 效果展示
为了让大家看到清晰的效果展示,这里分别上使用默认ObjecFactory和自定义ObjectFactory的断点图:
使用默认ObjecFactory也就是DefaultObjectFactory的效果图:
在这里插入图片描述
从图中可以清晰看到创建的Blog对象属性是没有值的
再来看看使用自定义CustomObjectFactory的效果图:
在这里插入图片描述
从图中可以看出这里的Blog对象中各属性是已经赋值了的,了解了ObjectFactory的基本使用,接着来看下MyBatis是如何解析的

三、objectFactory 解析

为什么说DefaultObjectFactory就是MyBatis中的默认的对象工厂呢?我们在Configuration配置类就可以看出:

public class Configuration {
	// ....
  protected ObjectFactory objectFactory = new DefaultObjectFactory();
  	// ....
}

MyBatis在解析配置文件初始化Conuration的时候就创建了一个默认的ObjectFactory实现;
既然有了默认的实现,那我们自定义的ObjectFactory又是什么时候被解析到MyBatis中的呢?我们去看一下配置文件的解析:
当我们在使用SqlSessionFactoryBuilder的build方法 构建 SqlSessionFactory 的时候,会对Mybatis的核心配置文件进行解析

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

在SqlSessionFactoryBuilder的build方法中会使用 XMLConfigBuilder 的 parse()方法对配置文件进行解析

public class SqlSessionFactoryBuilder {
	// ....
	  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
	//.....
}

在 parse()方法中,parseConfiguration()方法会选取configuration根标签开始解析

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

objectFactoryElement()方法对objectFactory 标签进行解析

  private void parseConfiguration(XNode root) {
    try {
      //....这里只看objectFactory的解析
      objectFactoryElement(root.evalNode("objectFactory"));
      //....
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
  private void objectFactoryElement(XNode context) throws Exception {
    //如果配置了objectFactory标签就解析,否则使用默认ObjectFactory
    if (context != null) {
      //获取type属性值
      String type = context.getStringAttribute("type");
      //解析property子标签
      Properties properties = context.getChildrenAsProperties();
      //创建ObjectFactory实例
      ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      //设置properties属性,这里就是将property子标签中配置的值,设置到了自定义的ObjectFactory中
      factory.setProperties(properties);
      //赋值,使用我们自定义的ObjectFactory
      configuration.setObjectFactory(factory);
    }
  }

这里我们也可以断点看下ObjectFactory的变化:
在这里插入图片描述

以上就是对objectFactory 标签的简单解析了,如有错误欢迎指出,希望对你有点帮助!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值