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

啃了一周tkmybatis源码,51张图,5个主要流程,构成了tkmybatis的源码组成 。tkmybatis包括了mybatis的部分,源码相比于mybatis多了个mApperscan的注解处理,其余部分是一致的 。理清了tkmybatis,就理清了mybatis源码,同时对mybatis的机制能有更深刻的认识 。
纯mybatis每个持久化操作都要写sql,会显得有些繁琐 。现在市面上也有很多的插件,比如mybatis逆向工程,mybatisCodeHelperPro等,可以在xml文件中生成一些常用的sql和对应的mapper接口方法 。也有一些mybatis的第三方工具框架,帮我们免去单表操作的sql编写,比如tkmybatis 。tkmybatis源码版本:
<dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot-starter</artifactId><version>2.1.5</version></dependency>一、tkmybatis使用案例
mybatis系列-5分钟教你提升CRUD开发效率200%
二、整体流程
tkmybatis流程大概分为以下几步:

  • 根据properties文件中配置的xml位置,为每个mapper接口生成一个MappedStatement对象(此时对象的SQLSource为不可执行的Provider)
  • 根据ScanMapper接口, 将接口加入到Spring 容器中,创建对应的BeanDefinition,然后修改BeanDefinition中的Bean类型为MapperFactoryBean
  • Spring容器实例化MapperFactoryBean实例,在初始化方法中,获取第一步每个接口生成的MappedStatement对象,并将MappedStatement对象的SQLSource修改为可执行的SqlSource(Provider生成xml格式的SQL,根据该SQL利用languageDriver创建新的sqlSource)
  • 将mapper的bean实例注入到需要依赖该实例的service中,此时会Spring容器调用MapperFactoryBean的getObject方法,该方法创建了一个mapper的代理类(使用jdk的动态代理方法),并注入到service里面去
  • 执行SQL时,对mapper的SQL操作,都由mapper的代理类mapperProxy来实现,实现过程跟原生mybatis用sqlsession创建的代理类一样的,只是这里没有显示的使用sqlsession来创建代理类,而是放到了MapperFactoryBean的getObject里面,将生成的代理类注入给service
三、源码解析:1、Mapper接口扫描:a、接口扫描入口位置
入口@MapperScan
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
这个注解会@Import进来一个tk.mapper的扫描器(将MapperScannerRegistrar导入到到Spring容器中,并将其声明成一个bean,该类的功能是处理注解MapperScan,具体过程见后面)
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
MapperScannerRegistrar实现了spring的
ImportBeanDefinitionRegistrar接口, 并实现了registerBeanDefinitions方法 。【注:如下图Spring容器在初始化的时候,会先扫描基本注解如controller等,然后扫描第三方jar包中的组件,扫描完成后再找到实现了
ImportBeanDefinitionRegistrar接口的Bean,并将当前的AnnotationMetadata和BeanDefinitionRegistry作为参数传入,通过该Bean扫描自定义注解的组件进来】
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
该bean在实例化的时候,会调用registerBeanDefinitions方法来扫描并导入mapper接口,接着来看下扫描过程 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
b、创建扫描器并利用MapperScan参数初始化该扫描器
该步骤创建一个扫描器, 利用MapperScan参数初始化该扫描器,各参数意义后面说,默认为空也没关系 。同时还会根据MapperScan参数确定扫描package的范围 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 

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

文章插图
 
c、注册扫描器filter之所以把这个单独提出来,是因为这一步决定了scanner能扫描出哪些mapper,符合filter条件的就会被扫描出来 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字

文章插图
 
看下registerFilters的具体实现:在registerFilters中,扫描器会添加includeFilter和excludeFilter,如果扫描出来的类在某一个excludeFilter中,则放弃该类,如果扫描出来的类在某一个includeFilter中,则保存该类到扫描的返回结果中,excludeFilter要先于includeFilter进行判断 。详见(
ClassPathScanningCandidateComponentProvider的isCandidateComponent方法) 。
下图中annotationClass和markerInterface都是在前面初始化扫描器的时候,通过MapperScan注解传入的 。
亲自啃了一周,终于把Mybatis源码理清,以后简历请写精通二字


推荐阅读