Mybatis系列(七)objectFactory源码解析


上篇文章 Mybatis系列(六)typeHandler源码解析,对mybatis的类型转换器有了简单的认识,除了我们使用默认提供的typeHandler之外,在平时的项目中,也经常用到自定义的枚举typeHandler,今天这节我们来看看mybatis的对象工厂(objectFactory)是怎么一回事。

依旧从XMLConfigBuilder解析xml配置文件中的objectFactory节点看起

一、objectFactoryElement源码

    private void objectFactoryElement(XNode context) throws Exception {
        if (context != null) {
        	//type属性,获取type节点指定对应的对象工厂
            String type = context.getStringAttribute("type");
            Properties properties = context.getChildrenAsProperties();
            //创建ObjectFactory,依旧是创建别名的这个方法resolveClass
            ObjectFactory factory = (ObjectFactory)this.resolveClass(type).newInstance();
            factory.setProperties(properties);
            //放入configuration,备用
            this.configuration.setObjectFactory(factory);
        }

    }
ObjectFactory 接口
public interface ObjectFactory {
    void setProperties(Properties var1);

    <T> T create(Class<T> var1);

    <T> T create(Class<T> var1, List<Class<?>> var2, List<Object> var3);

    <T> boolean isCollection(Class<T> var1);
}

从接口的定义看,接口有两个通过反射实现得构造函数,另外,为了使的这个工厂类能接收设置的附带属性,还提供了setProperties()方法。

当创建结果集时,mybatis会使用一个对象工厂来完成创建这个结果集实例。在默认的情况下,mybatis会使用其定义的对象工厂——DefaultObjectFactory来完成相应的工作,有兴趣的可以看一下源码的实现类,其实它创建实例对象最终都是通过instantiateClass()方法能实现的,下边会讲到。

ObjectFactory是不是很简单,看到这里可能会问前两节讲的typeAliasestypeHandler,mybatis都提供了默认的配置,并且支持自定义的typeAliasestypeHandler,那么ObjectFactory是否也支持自定义呢?答案是肯定的。下边我们就创建一个自定义的ObjectFactory——MyObjectFactory

二、自定义ObjectFactory

如果自定义需要实现接口ObjectFactory,并给予配置。在大部分情况下,我们不需要自定义返回规则,因为这些比较复杂容易出错,在更多情况下,都会考虑系统已经实现的DefaultObjectFactory,通过继承它来完成我们需要的工作。

public class MyObjectFactory extends DefaultObjectFactory {

    private static final long serialVersionUID = -7924251036323382165L;

   Logger logger = Logger.getLogger(MyObjectFactory.class);

    private Object temp = null;

    public void setProperties(Properties properties) {
        super.setProperties(properties);
        logger.info("初始化参数:--------"+properties.toString());
    }

    //方法2
    public <T> T create(Class<T> type) {
        T result = super.create(type);
        logger.info("创建对象:--------"+result.toString());
        logger.info("是否和上次创建的是同一个对象:【"+temp.equals(result) +"】");
        return result;
    }

    //方法1
    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
        T result = super.create(type, constructorArgTypes, constructorArgs);
        logger.info("创建对象:--------"+result.toString());
        temp = result;
        return result;
    }

    public <T> boolean isCollection(Class<T> type) {
        return super.isCollection(type);
    }
}

三、objectFactory在mybatis-config.xml的配置

    <objectFactory type="com.sean.factory.MyObjectFactory">
        <property name="prop1" value="value1"/>
    </objectFactory>

这样mybatis就会采用配置的MyObjectFactory来生成结果集对象,我们测试一下:

四、自定义objectFactory测试

测试代码,依旧是前几节用过的findUserById

    public void findUserByIdTest(){
        SqlSession sqlSession = getSessionFactory().openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.findUserById(1L);
        logger.debug(user.getName());
    }

日志打印:
在这里插入图片描述
如果打断点调试,会发现mybatis创建了一个List对象和一个User对象,它会先调用方法1,然后调用方法2,只是最后生成了同一个对象,所以在写入的判断中,始终返回的是true,因为返回的是同一个User对象,所以它会最后适配为一个User对象,这就是它的工作过程。

为什么会创建一个List对象和一个类对象?请看这个方法

resolveInterface
    protected Class<?> resolveInterface(Class<?> type) {
        Class classToCreate;
        //判读是否集合,比如我们传入User,那么就直接返回类对象
        if (type != List.class && type != Collection.class && type != Iterable.class) {
            if (type == Map.class) {
                classToCreate = HashMap.class;
            } else if (type == SortedSet.class) {
                classToCreate = TreeSet.class;
            } else if (type == Set.class) {
                classToCreate = HashSet.class;
            } else {
            	//直接返回对象
                classToCreate = type;
            }
        } else {
        	//直接返回List对象
            classToCreate = ArrayList.class;
        }

        return classToCreate;
    }

objectFactory节点就讲到这里,平时开发中,用到的也比较少,大致了解下怎么回事即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis是一个轻量级的Java持久层开源框架,它封装了JDBC操作数据库的底层细节,提供了一个简单易用的数据库访问方式。 Mybatis源码分为核心模块和附加模块两部分,核心模块主要包括配置解析、SQL解析、SQL执行等功能,附加模块包括连接池、缓存、事务管理等功能。 在Mybatis源码中,配置解析是其中的关键部分。通过解析mybatis-config.xml配置文件,可以获取到数据库连接信息、映射器配置、插件配置等。在配置解析过程中,Mybatis会对配置文件进行校验,确保配置的正确性。 SQL解析Mybatis的另一个重要功能。Mybatis通过解析Mapper接口中的注解或XML配置文件中的SQL语句,将SQL语句解析为ParameterMapping、BoundSql等对象,并将其封装成一个MappedStatement对象,供后续的SQL执行使用。 SQL执行是Mybatis的核心功能之一。在SQL执行阶段,Mybatis会根据MappedStatement中的信息,获取数据库连接,并执行对应的SQL语句。在执行过程中,Mybatis会通过TypeHandler对参数进行类型转换,并使用ResultSetHandler将查询结果封装成Java对象。 除了核心模块,Mybatis源码还包括了连接池、缓存、事务管理等附加模块的实现。连接池模块负责管理数据库连接的获取和释放,缓存模块负责缓存查询结果以提高性能,而事务管理模块则负责管理数据库的事务处理。 总之,Mybatis源码解析涉及多个关键模块的实现,包括配置解析、SQL解析、SQL执行、连接池、缓存、事务管理等。通过了解这些模块的实现原理,我们可以更好地理解和使用Mybatis框架。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值