Mybatis 原理分析(SpringBoot)

前言

在学习之前需要复习以下知识:

  • 动态代理
  • JDBC操作
  • 了解Spring容器的创建流程

一、向Spring容器中注入Mapper接口代理对象

1.注册MapperScannerConfigurer组件的 BeanDefinition ,并在void registerBeanDefinitions 方法中为MapperScannerConfigurer组件设置@MapperSacn注解中所配置的属性信息;

MapperScannerRegistrar.java
Mybatis 原理分析(SpringBoot)_第1张图片

2.MapperScannerConfigurer组件实现了BeanDefinitionRegistryPostProcessor (spring扩展接口),public void postProcessBeanDefinitionRegistry()方法 - 用于加载用户的自定义配置(一般可以在配置文件中配置多数据源的sqlSessionFactory)以及它会查找类路径下的映射器并自动将它们创建成 MapperFactoryBean(MapperFactoryBean 会将Mapper接口代理对象注入到Spring容器中)。

MapperScannerConfigurer.java
Mybatis 原理分析(SpringBoot)_第2张图片
在上面的后置处理器方法中创建了ClassPathMapperScanner对象,并调用了scanner.scan()方法对指定映射包下的Mapper接口进行扫描。

3.ClassPathMapperScanner重写了父类的doScan()方法,调用父类ClassPathBeanDefinitionScannerdoScan()方法获取到指定包下的所有 Mapper接口的BeanDefinition并返回,并且注册了Mapper接口的BeanDefinition。

ClassPathBeanDefinitionScanner.java
Mybatis 原理分析(SpringBoot)_第3张图片

4.ClassPathMapperScannerprocessBeanDefinitions()方法中修改了这些 Mapper接口的 beanclass 为MapperFactoryBean。

Mybatis 原理分析(SpringBoot)_第4张图片
Mybatis 原理分析(SpringBoot)_第5张图片

5.由于SpringBoot在Mybatis自动配置文件中已经配置了SqlSessionTemplate、SqlSessionFactory的bean,所以我们无需配置。

Mybatis 原理分析(SpringBoot)_第6张图片
Mybatis 原理分析(SpringBoot)_第7张图片

6.Spring会自动装配MapperFactoryBean所需要的对象,在注入了 SqlSessionTemplate、SqlSessionFactorybean之后,会调用setSqlSessionFactory()方法为每个 MapperFactoryBean对象注入sqlSessionTemplate

SqlSessionDaoSupport.java
在这里插入图片描述

7.在MapperFactoryBean的属性设置之后,就会调用checkDaoConfig()方法。

MapperFactoryBean.java
Mybatis 原理分析(SpringBoot)_第8张图片

8.接下来正式到了mybatis的核心,通过MapperFactoryBeangetObject()方法向Spring容器注入不同Mapper接口代理对象。

MapperFactoryBean.java
在这里插入图片描述

9.调用SqlSessionTemplategetMapper(Class type)方法,通过封装在SqlSessionTemplate中的配置类Configuration获取代理对象。

SqlSessionTemplate.java
在这里插入图片描述

10.最终通过不断的调用,使用mybatisMapperRegistry来获取 Mapper接口的代理对象。

Mybatis 原理分析(SpringBoot)_第9张图片

11.在knownMappers中保存了每个类型的Mapper对应的MapperProxyFactory代理工厂,调用mapperProxyFactory.newInstance(sqlSession)创建代理对象。

MybatisMapperRegistry.java
Mybatis 原理分析(SpringBoot)_第10张图片

12.最终会创建一个代理对象,mapperProxy中实现了动态代理的调用处理方法。

MybatisMapperProxyFactory.java
Mybatis 原理分析(SpringBoot)_第11张图片
至此一个Mapper接口的代理对象就注入到了Spring容器当中。

二、代理对象的执行流程

接下来分析在MybatisMapperProxyinvoke()方法做了什么。

1.当调用Mapper接口代理对象时,代理对象就会执行invoke()方法。

MybatisMapperProxy.java
Mybatis 原理分析(SpringBoot)_第12张图片

2.调用mapperMethod.execute(sqlSession, args)方法,根据SQL类型,使用sqlSession调用不同的方法(这里的sqlSession就是Spring整合mybatis创建的SqlSessionTemplate)。

Mybatis 原理分析(SpringBoot)_第13张图片

3.分析SELECT分支,调用链进入到SqlSessionTemplate其中的一个selectOne方法,可以发现在SqlSessionTemplate中使用了sqlSessionProxy代理对象调用的方法(后面会分析为何要使用代理对象调用)。

在这里插入图片描述

4.接下来会先执行sqlSessionProxy代理对象的invoke()方法,获取DefaultSqlSession对象,并使用DefaultSqlSession对象来执行SQL操作。

Mybatis 原理分析(SpringBoot)_第14张图片

5.沿着调用链来到了DefaultSqlSessionselectList()方法,使用configuration获取到了MappedStatement对象,这里面封装了需要执行的SQL语句等信息,通过执行器将MappedStatement以及SQL参数parameter等传入方法。

Mybatis 原理分析(SpringBoot)_第15张图片

6.经过漫长的调用链最终会进入到MybatisSimpleExecutordoQuery方法,可以看到熟悉的JDBC操作,并且会在prepareStatement()方法中获取数据库连接,并返回一个Statement,最终调用PreparedStatement对象执行SQL语句。

Mybatis 原理分析(SpringBoot)_第16张图片
在这里插入图片描述
Mybatis 原理分析(SpringBoot)_第17张图片

三、总结

前面两部分可以大致分为 Mapper接口代理对象的创建,以及代理对象的对SQL语句的执行。

  • Mapper接口代理对象的创建:Spring通过@MapperScan注解获取到所有的Mapper接口,通过MapperScannerRegistrar向容器中注册了一个MapperScannerConfigurer组件并为其设置了注解属性信息,在这个组件中创建了ClassPathMapperScanner对象扫描指定包下的Mapper接口组件还将设置的属性信息也设置到了ClassPathMapperScanner对象中,ClassPathMapperScanner对象将扫描到的Mapper接口的beanDefinition的beanclass修改为MapperFactoryBeanMapperFactoryBean通过getObject()方法调用SqlSessionTemplate.getMapper(this.mapperInterface)方法返回Mapper接口的动态代理对象;
  • 代理对象对SQL语句的执行:代理对象在invoke()方法中获取到调用方法类型并根据SQL类型执行DefaultSqlSession不同的SQL方法,在DefaultSqlSession中封装了Configuration对象,它会获取到MappedStatement对象(包含了需要执行的SQL语句),后面会获取数据库连接使用PreparedStatement对象执行SQL语句。

四、补充

1.前面我们提到在SqlSessionTemplate调用SQL方法时,真正执行的是封装在SqlSessionTemplate里的sqlSessionProxy动态代理对象,使用代理对象执行SQL方法的目的是保证线程安全(DefaultSQLSession不是线程安全的),具体参考:SqlSessionTemplate是如何保证MyBatis中SqlSession的线程安全的?

你可能感兴趣的:(Spring,mybatis)