MyBatis 执行流程及源码解析
先看一个简单的例子,以Service调用Mapper接口为例:
public interface StudentMapper {
@Select("select * from student")
public List<Map<String,Object>> query();
}
@Service("studentService")
public class StudentServiceImpl implements StudentService {
@Autowired
StudentMapper studentMapper;
@Override
public List<Map<String, Object>> query() {
return studentMapper.select();
}
}
向Service中注入这个Mapper并调用时,你知道这时注入的是什么吗?
一、配置SqlSessionFactoryBean 时都做了什么?
在进行spring和mybatis整合时,会用xml或者注解的方式去配置一个SqlSessionFactoryBean,本文中以注解方式为例:
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
看一下SqlSessionFactoryBean的继承实现关系:
先看spring中两个非常重要的接口,FactoryBean和InitializingBean。
FactoryBean:
在这里用于创建并返回一个SqlSessionFactory,在 spring +mybatis 的环境下,我们使用SqlSessionFactoryBean来充当SqlSessionFactory。
InitializingBean:
通过调用SqlSessionFactoryBuilder的build方法,最终返回了一个DefaultSqlSessionFactory实例,这个DefaultSqlSessionFactory中保存了一个非常重要的Configuration对象。
二、@MapperScan都做了什么?
在注解配置mybatis时,通过@MapperScan指定Mapper存放的包,就能自动为我们把接口实现成类。那么这是怎么实现的呢?
点开@MapperScan的源码,发现上面还有一行非常重要的注解:
@Import(MapperScannerRegistrar.class)
ImportBeanDefinitionRegistrar接口提供registerBeanDefinitions方法向用户暴露了BeanDefinitionRegistry,也就是说可以让用户手动创建BeanDefinition并使用该注册器注册到spring容器中。
查看MapperScannerRegistrar的方法registerBeanDefinitions中的核心代码:
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
……
scanner.doScan(StringUtils.toStringArray(basePackages));
主要是创建了一个Mapper扫描器,开启扫描。
ClassPathMapperScanner中doScan方法:
这里对生成的mapper的bean定义做了进一步处理
进入processBeanDefinitions()方法:
注意画框代码及上方的注释,先看一下从BeanDefinitionHolder获得BeanDefinition时beanClass初始的值:
等待setBeanClass执行完毕:
通过definition.setBeanClass()把原来的BeanClass的类型替换成了MapperFactoryBean类型。到这,完成了Mapper接口加载定义阶段中非常重要的一步,而这也是生成代理对象MapperProxy的关键。
三、mybatis如何生成代理对象?
看一下MapperFactoryBean的继承关系:
MapperFactoryBean继承的SqlSessionDaoSupport类实现了InitializingBean接口,那么我们还是首先找afterPropertiesSet()方法:
DaoSupport中,最终调用MapperFactoryBean中的方法:
首先通过获取sqlSession获得了非常重要的配置类Configuration,然后查看一下addMapper方法,最终调用的是MapperRegistry的addMapper方法:
红框中的代码为我们创建了Mapper 的代理工厂对象(还不是Mapper的代理对象),并把它放入了knownMappers这个Map中。
MapperFactoryBean最终返回了什么?
因为MapperFactoryBean实现了FactoryBean接口,所以我们看看getObject方法究竟返回了什么:
最终调用MapperRegistry的getMapper方法:
至此,我们已经弄明白了文章开头的MapperProxy是如何生成的。
四、MapperProxy代理对象如何执行sql语句?
在这里最终调用了MapperMethod的execute方法实际去执行了sql语句。
扫码关注公众号
有趣、深入、直接
与你聊聊java
公众号后台回复“面试”,领取大厂面试资料
觉得有用,点个在看吧~