这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战
Mybatis基于Mapper源码解析
Mapper代码实现
由于基于Mapper代理方式前三步和基于XML配置实现方式一样,这次不过多讲解。
强调一点:MyBatis初始化时对接⼝的处理:MapperRegistry是Configuration中的⼀个属性,它内部维护⼀个HashMap⽤于存放mapper接⼝的⼯⼚类,每个接⼝对应⼀个⼯⼚类。mappers中可以配置接⼝的包路径,或者某个具体的接⼝类。
<mappers>
<mapper class="com.mybatis.mapper.UserMapper"/>
<package name="com.mybatis.mapper"/>
</mappers>
- 当解析mappers标签时,它会判断解析到的是mapper配置⽂件时,会再将对应配置⽂件中的增删改查标签封装成MappedStatement对象,存⼊mappedStatements中。
如果mapper里面是package标签,那么会通过configutation类中的addMappers实现类进行扫描该包下的所有Mapper接口,并添加到mapperRegistry中
通过XMLConfigBuilder类中的mapperElement方法进行解析MapperXMl文件的相关信息。 当判断解析到接⼝时,会建此接⼝对应的MapperProxyFactory对象,存⼊HashMap中,key=接⼝的字节码对象,value =此接⼝对应的MapperProxyFactory对象。
getMapper源码解析
首先进入sqlSession.getMapper(UserMapper.class)中
getMapper的实现类是DefaultSqlSession类,在该类中getMapper方法调用了configuation中的getMapper方法,进入该方法中源码如下图所示:
configuation中的getMapper方法的实现类是MapperRegistry的getMapper方法,进入该方法源码如下图所示:
通过传入的参数type值查询map集合获取到MapperProxyFactory,MapperProxyFactory在初始化的过程中,每一个Mapper都会生成对应的MapperProxyFactory并存放的map集合中,如果为空,则直接抛出异常,如果不为空,直接调用mapperProxyFactory.newInstance()方法进行动态代理工厂生成实例。进入该方法源码如下所示:
使用Proxy.newProxyInstanc()方法调用动态代理,由此可见,sqlSession.getMapper()方法底层就是调用的是JDK的动态代理的实现。然后接收到的就是对应mapper的代理对象
MapperProxy中invoke()方法解析
在动态代理返回了示例后,我们就可以直接调⽤mapper类中的⽅法了,但代理对象调⽤⽅法,执⾏是在MapperProxy中的invoke⽅法中
通过上图代码可以,主要invoke方法主要调用的是mapperMethod.execute()方法。
基本上execute最终的还是调用的SqlSession中的增删差改方法,而且查询方法还区分了很多方法,具体看源码注释。
由此可知,invoke方法底层还是调用SqlSession方法。