一、概述
- Mybatis 通过解析 XML 文件,将每一个标签封装成为一个个 MappedStatement,而后在调用的时候,通过动态代理进行实现
二、初始化
-
Mybatis 通过 建筑者 模式进行创建
-
首先我们要知道每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
1、SqlSessionFactory和SqlSessionFactorybean
-
openSession
方法是为了获取一个SqlSession对象,完成必要数据库增删改查功能; -
getConfiguration
的配合;来配置mapper映射文件、SQL参数、返回值类型、缓存等属性。
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
-
日常开发中我们都是将Mybatis与Spring一起使用的,所以把实例化交给Spring处理。
-
org.mybatis.spring.SqlSessionFactoryBean
,它实现了InitializingBean接口 -
这说明,在这个类被实例化之后会调用到afterPropertiesSet()。它只有一个方法
public void afterPropertiesSet() throws Exception {
this.sqlSessionFactory = buildSqlSessionFactory();
}
-
buildSqlSessionFactory
。它可以分为两部分来看: -
1、从配置文件的property属性中加载各种组件,解析配置到configuration中
-
2、加载mapper文件,解析SQL语句,封装成MappedStatement对象,配置到configuration中。
(1) MappedStatement 对象,
- 存在两个最重要的属性
- id
- 全限定类名+方法名组成的ID
- sqlSource
- 当前SQL标签对应的SqlSource对象。
- id
- 将其存放到
Configuration#mappedStatements
对象中,后续可以通过 id 直接索引到 对应的 sqlSource 对象
2、dao 动态代理
(1)包扫描路径
@MapperScan({"com.mmzsblog.business.dao"})
(2)开始扫描
- 具体在 BeanDefinitionRegistryPostProcessor() 这个类中,去调用 doScan()方法,将会扫描到所有的 Mapper 接口,源码不细讲了,具体自己看
(3)注册 BeanDefinition
- 将所有扫描到的 Mapper 接口注册成为 BeanDefinition 对象,这样子就可以进行初始化
(4)动态代理
- 在setSqlSessionFactory这个方法里,sqlSession获取到的是SqlSessionTemplate实例。而在SqlSessionTemplate对象中,主要包含sqlSessionFactory和sqlSessionProxy,而sqlSessionProxy实际上是SqlSession接口的代理对象,实际调用的是代理类的invoke方法。
题外话: 如果我们主动实现了 dao 接口,然后又配置了 mapper 会发生什么? 这时候,在使用 ioc 容器中将会存在两个 dao 接口的实现类,你需要自己指定注入的对象是那个
3、执行
- 当我们调用Dao接口方法的时候,实际调用到代理对象的invoke方法。 在这里,实际上调用的就是SqlSession里面的东西了
public class DefaultSqlSession implements SqlSession {
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms,
wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}
}
}
- 通过statement
全限定类型+方法名
拿到MappedStatement 对象,然后通过执行器Executor去执行具体SQL并返回。
三、总结
- SqlSource以及动态标签SqlNode
- MappedStatement对象
- Spring 工厂Bean 以及动态代理
- SqlSession以及执行器