亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字( 四 )


亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
到这里mapper解析的操作就完成了,MapperFactoryBean中的configuration保存了每一个mapper方法的mappedStatement以及已知的mapper类 。
c、为每个方法对应的MappedStatement更新SqlSource
我们再回到MapperFactoryBean类,来看看它的checkDaoConfig方法都做了些什么 。先把结论说了吧,checkDaoConfig会根据mapper接口将每个接口方法对应的sqlSource,由前面说的ProviderSqlSource转换成languageDriver创建的sqlSource(可以理解为tkMybatis根据每个方法的定义,利用Provider为每个方法在对应的mapper.xml中添加了方法对应的SQL语句,然后利用修改后的xml创建新的sqlSource,更新到MappedStatement里面去,只有更新后的MappedStatement,才能执行Mybatis的SQL处理 。当然实际上是没有直接修改xml文件这一步的,只是打个比方,可以看后面的代码实现) 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
再继续看processConfiguration方法做了什么操作 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
再继续看processMappedStatement对MappedStatement的处理,该处理中会对MappedStatement中的SqlSource进行替换 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
看一下替换前,MappedStatement中的SqlSource如下图所示,是个Provider实现类 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
执行setSqlSource后,在下图中可以看见,MappedStatement中的sqlSource参数已经变成了DynamicSqlSource 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
接下来,我们继续看下setSqlSource到底是怎么改变sqlSource的 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
继续看mapperTemplate的setSqlSource方法,该方法完成了xml形式sql的创建和对应sqlSource的创建 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
跟进method.invoke方法,可以发现,该方法实际是在mapper接口方法对应的Provider实现类中执行的,如下图selectByExample方法由ExampleProvider来生成xmlsql 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
至此,tkMybatis就在checkDaoConfig方法中将接口方法对应的MappedStatement中的sqlSource由不能执行的Provider实现类,转换成了Mybatis中的可执行的sqlSource(根据xmlSql生成,和mybatis扫描mapper.xml文件中创建的MapperStatement和SqlSource具有同样的功效!)
到目前为止,经过1、Mapper接口扫描和2、Mapper 接口Bean的实例化就完成了tkMybatis的初始化工作 。
3、将Mapper实例注入到依赖该实例的bean中
前面tkMybatis做了两件事情,一是扫描Mapper接口比如UserMapper,创建对应的Bean定义,并将其中的类型修改为MapperFactoryBean;二是实例化该Bean,因为类型已经修改为MapperFactoryBean,就完成MapperFactoryBean的实例化和初始化 。
接下来还有关键的一步,怎么用这个Bean,我们在写service的时候,会通过@autowired注解将Mapper注入到service中,比如下面的:
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
以UsersMapper举个例子,Spring在注入UsersMapper时,会调用对应MapperFactoryBean实例的getObject方法,如下图,在该方法中,会创建UsersMapper的的代理类,进入getmapper这个方法,会跟到前面第2部分knowMappers部分,getmapper是从knowMappers获取的Mapper,该Mapper是一个Mapper接口的代理类MapperProxy,对UserMapper的方法调用都会有MapperProxy的invoke方法来实现 。
这也就解决了“明明是Mapper的接口比如UserMapper,但是在bean定义中把它的类型改成了MapperFactoryBean,MapperFactoryBean又没有实现Mapper的接口方法,那么service中注入的mapper调用方法的时候是如何调用的问题” 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
4、实际SQL语句的执行
接着上一部分,调试下实际执行SQL语句的过程 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 

亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
其实,像下图一样,使用经过注入后的Mapper代理类,就跟原生Mybatis创建的代理类是一样的,执行的SQL操作的过程也是一样的 。里面的每个接口方法也都有对应的MappedStatement实现 。如果对invoke代理的过程感兴趣,可以调试跟进去看,看看如何invoke中如何用MappedStatement做具体的SQL处理,这里就不具体说了 。


推荐阅读