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 标签的简单解析了,如有错误欢迎指出,希望对你有点帮助!