环境:
| 1 | mybatis-spring-boot-starter: 1.3.4 | 
在MybatisAutoConfiguration类中查看Mybatis的SqlSessionFactory接口的实现DefaultSqlSessionFactory是如何注册到Spring容器的。
由于不是本文重点,这里就不贴源码了,描述下大概流程:
Mybatis是通过SqlSessionFactoryBean工厂bean的方式获取bean实例的。
首先通过SqlSessionFactoryBean类的buildSqlSessionFactory方法中调用xmlMapperBuilder.parse()方法
将Mapper接口的Class类型作为key,MapperProxyFactory实例作为value注册到MapperRegistry类上。
然后将MapperRegistry实例设置到Configuration类的mapperRegistry属性上。
最后调用SqlSessionFactoryBuilder类的build方法完成SqlSessionFactory实例的创建:
| 1 | public SqlSessionFactory build(Configuration config) { | 
这里看下MapperProxyFactory类的源码:
| 1 | public class MapperProxyFactory<T> { | 
可以看到通过调用MapperProxyFactory的newInstance方法完成Mapper接口代理的生成。这里用到了Jdk的动态代理。
这里说明一点,Mybatis和Spring整合使用SqlSession的实现是SqlSessionTemplate,它是线程安全的由Spring管理的单例bean。
当调用Mapper接口的方法时,实际上会调用MapperProxy代理的invoke方法:
| 1 | @Override | 
然后返回调用MapperMethod类的execute方法:
| 1 | public Object execute(SqlSession sqlSession, Object[] args) { | 
可以看到这里通过命令模式处理对应的Sql。这里笔者选择执行一条查询命令,那么最终会调用该类的executeForMany方法:
| 1 | private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { | 
接下来进入SqlSessionTemplate的selectList方法:
| 1 | @Override | 
可以看到其实是调用的SqlSession的代理来调用实际的selectList方法。
查看SqlSessionTemplate类的构造方法的源码有这一行:
| 1 | this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), | 
可知SqlSessionTemplate持有SqlSession接口的代理,其默认实现是DefaultSqlSession。查看该类的selectList方法实现:
| 1 | @Override | 
由于Mybatis默认是打开本地缓存的,即每个Session都持有Executor的引用实现CachingExecutor。
接下来进入CachingExecutor的query方法:
| 1 | @Override | 
进入BaseExecutor的query方法实现,有这么一行:
| 1 | list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); | 
继续查看queryFromDatabase方法实现,有这么一行:
| 1 | list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); | 
由于默认使用Mybatis的ExecutorType是SIMPLE,所以进入SimpleExecutor的doQuery方法实现:
| 1 | @Override | 
第一点,查看实现会返回RoutingStatementHandler实例,由于默认的语句类型是StatementType.PREPARED,
所以该类持有PreparedStatementHandler对象的引用。
第二点,prepareStatement方法实现:
| 1 | private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { | 
PreparedStatementHandler的parameterize方法会调用DefaultParameterHandler的setParameters方法处理参数映射:
| 1 | @Override | 
第三点,委托调用PreparedStatementHandler的query方法:
| 1 | @Override | 
这里重点看下结果的映射,结果的类型处理和参数的类型处理都是基于TypeHandler接口的实现,可以看看其抽象类的实现BaseTypeHandler:
| 1 | @Override | 
这里getNullableResult方法是抽象方法,将由具体的子类实现。比如有个实体的属性是
| 1 | private LocalDateTime createAt; | 
那么将会使用LocalDateTimeTypeHandler类的实现,也可以指定自己的TypeHandler实现,在<resultMap>标签
的子标签<result>自定义typeHandler:
| 1 | <result property="createAt" column="create_at" typeHandler="org.apache.ibatis.type.LocalDateTimeTypeHandler"/> | 
到此,Mybatis的调用流程源码分析结束。
以上,如有问题欢迎提出!

