Springboot整合MyabatisPlus实质就是Spring加载MybatisPlus过程,只不过Springboot的自动装配,帮做了很多Spring以前需要手动配置的Bean到Spring容器中,自动装配类:MybatisPlusAutoConfiguration,核心Bean为:SqlSessionFactory,SqlSessionTemplate,MapperScannerConfigurer。本次主要想分析下加载Mapper过程,最近写Junit单测无法Mock,MybatisPlus的LambdaQueryChainWrapper,然后跟了一波源码,记录下收获。该篇幅不做很详细介绍源码的每一块和Mybatis的各个组件,流程等,只是介绍有无xml的情况下,BaseMapper如何加载的过程。
MyabtisPlus版本3.5.1
一、加载配置有xml文件的Mapper或者Dao
Dao或者Mapper表示持久层,都是公司的一些规范,怎么舒服怎么来,只需要配置xml的namespace跟Dao或者Mapper的引用地址一致,都能调用到xml的sql,Springboot启动时候加载xml是在创建SqlSessionFactory的Bean时加载,
步骤一:创建MybatisSqlSessionFactoryBean不是Spring的SqlSessionFactoryBean,创建MybatisConfiguration,也不是Mybatis的Configuration,但是MybatisConfiguration是继承Configuration,重写了addMappedStatement方法
步骤二:从创建SqlSessionFactory的代码跟下来,很多都是配置信息(可忽略),最后看到factory.getObject(),创建Bean的同时,就会做xml的解析,关键方法步骤:
factory.getObject(),afterPropertiesSet(),buildSqlSessionFactory()
步骤三:一直往下走,直到判断mapperLocations的位置,如果配置了扫描xml路径且有xml文件,就会进入xmlMapperBuilder.parse()
步骤四:如果步骤三没有配置xml扫描路径,和系统中没有配置xml文件,则会执行完整个SqlSessionFactory的Bean创建流程,返回一个DefaultSqlSessionFactory,并且打印logo,结束
步骤五:扫描xml文件,从xmlMapperBuilder.parse()进入,关键方法步骤:bindMapperForNamespace(),configuration.addMapper(),mybatisMapperRegistry.addMapper(),此时进入的是MybatisConfiguration,parser.parse()
步骤六:type为解析xml路径时候,读取到的每一个Mapper的接口,type.getMethods为接口中的方法,此时如果继承了BaseMapper,则BaseMapper中的方法,也会获取到,for循环一个个方法开始解析,为啥这只有一个type?可以回到步骤三中,是循环mapperLocations中进来的
步骤七:从步骤六中的parseStatement()进入,会看到熟悉的Mybatis解析xml的流程了,创建MappedStatement,然后加到Configuration中(不熟悉的朋友可以自行阅读),关键方法:assistant.addMappedStatement(),configuration.addMappedStatement(statement)
步骤八:步骤六中的parserInjector(),才是本次关注重点,BaseMapper接口无xml配置,生成模板方法
进入inspectInject,是一个抽象类AbstractSqlInjector,实现类是DefaultSqlInjector,继承关系如下图,从DefaultSqlInjector可以看到关键信息,是否跟BaseMapper里面的接口方法一致?所以答案就在此~~
滤一下过程,解析xml时候,会先解析xml里面自定义的sql,然后再对继承了BaseMapper的接口,且没有重写BaseMapper的方法,做模板sql注入。
每次inspectInject是以模板方法的模式,调用抽象方法获取DefaultSqlInjector的getMethodList,获取到List<AbstractMethod>的集合,抽象类AbstractMethod的每一个实现类,就是BaseMapper中的方法。遍历集合,然后执行AbstractMethod的inject,最后调用到具体实现类的injectMappedStatement,执行每一个实现类的具体逻辑,SqlMethod是该方法模板枚举,做sql替换,生成MappedStatement,放入Configuration中。
如有不清晰可以多跟几遍~~~
源码无法一步到位,多看,看多了就都明白了,其实也就那样,给我还是写不出来~~~哈哈哈!!!
二、无xml,扫描继承BaseMapper的接口
上面分析完了有xml的Mapper注入BaseMapper接口方法的过程,现在分析下无xml,又继承了BaseMapper在何时注入BaseMapper模板方法。
步骤一:从上面中可以知道,初始化Springboot是先执行SqlSessionFactory的Bean创建,且创建同时解析xml,然后才到Bean的初始化,注入属性参数。在启动类上面配置了@MapperScan,就会把配置路径下的Mapper接口做为一个Bean,加入到Spring容器,只要是Bean就要做实例化和初始化。Mapper接口扫描成Dao的时候,会做MapperFactoryBean的替换,此处不做该步骤解析。
步骤二:Bean的初始化Mapper时,doCreateBean会识别为Dao(此处为Spring初始化Bean过程,也不做分析),做Dao初始化时,由MapperFactoryBean的checkDaoConfig()方法执行,后续操作和有xml时是一样的步骤,生成BaseMapper模板方法,生成MappedStatement,放入Configuration中
三、总结
一顿分析之后,可以看出有无xml,BaseMapper加载的过程是差不多的,只不过时机不一样,入口不一样,同样实现了无需写xml方法,也可以实现单表的crud功能。Mybatis源码不算复杂,debug跟几遍,能学到里面设计模式巧妙使用方式,也可以学习设计思路,去拓展自己的视野!!!
网友评论