Spring整合Mybatis框架方法剖析

 更新时间:2023年07月13日 14:02:53   作者:王侦  
这篇文章主要为大家介绍了Spring整合Mybatis框架方法剖析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Spring整合其他框架的核心思路

就是将其他框架生成的类放到Spring容器中。同理,Spring整合Mybatis也是让Mybatis生成的Mapper接口的代理对象作为Bean注册到Spring容器中。

解决的核心问题

  • 1)通过FactoryBean创建Mapper接口代理对象,并且指定构造方法参数为Mapper接口class,并且设置BeanDefinition.setAutowireMode(AUTOWIRE_BY_TYPE)。
  • 2)通过ImportBeanDefinitionRegistrar或者BeanDefinitionRegistryPostProcessor中创建的扫描器实现对多个Mapper接口代理对象的创建和注册。
  • 3)扫描器筛选类时要重写isCandidateComponent(),第一个isCandidateComponent()总是返回true(因为添加一个TypeFilter,其match方法总是返回true。),第二个isCandidateComponent()如果为接口时返回true。

ClassPathMapperScanner#registerFilters这里面添加一个总是返回true的TypeFilter:

    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
    }

关于Mapper接口生成对象

  • 1.必须是一个对象(代理对象,JDK动态代理Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy))
  • 2.这个对象必须实现Mapper接口(动态代理对象必然实现Mapper接口)
  • 这两条由mybatis保证
  • 3.必须在spring容器当中

这条由mybatis-spring保证

1)FactoryBean,采用的就是这种方式,控制对象的生成过程,生成JDK动态代理对象

2)ac.getBeanFactory().registerSingleton(),也是一样麻烦

3)@Bean 方式,针对每一个接口都要一个@Bean,太麻烦

4)@Service 这样是把类交给Spring,然后创建对象,但是这里是接口,创建对象会报错,我们这里需要控制对象的生成过程(生成动态代理)

Mybatis-Spring 1.3.2版本底层源码执行流程

  • 1)通过@MapperScan导入了MapperScannerRegistrar类
  • 2)MapperScannerRegistrar类实现了ImportBeanDefinitionRegistrar接口,所以Spring在启动时会调用MapperScannerRegistrar类中的registerBeanDefinitions方法
  • 3)在registerBeanDefinitions方法中定义了一个ClassPathMapperScanner对象,用来扫描mapper
  • 4)设置ClassPathMapperScanner对象(继承自ClassPathBeanDefinitionScanner)可以扫描到接口,因为在Spring中是不会扫描接口的
  • 5)同时因为ClassPathMapperScanner中重写了isCandidateComponent方法,导致isCandidateComponent只会认为接口是备选者Component
  • 6)通过利用Spring的扫描后,会把接口扫描出来并且得到对应的BeanDefinition
  • 7)接下来把扫描得到的BeanDefinition进行修改,把BeanClass修改为MapperFactoryBean,把AutowireMode修改为byType
  • 8)扫描完成后,Spring就会基于BeanDefinition去创建Bean了,相当于每个Mapper对应一个FactoryBean
  • 9)在MapperFactoryBean中的getObject方法中,调用了getSqlSession()去得到一个sqlSession对象,然后根据对应的Mapper接口生成一个Mapper接口代理对象,这个代理对象就成为Spring容器中的Bean
  • 10)sqlSession对象是Mybatis中的,一个sqlSession对象需要SqlSessionFactory来产生
  • 11)MapperFactoryBean的AutowireMode为byType,所以Spring会自动调用set方法,有两个set方法,一个setSqlSessionFactory,一个setSqlSessionTemplate,而这两个方法执行的前提是根据方法参数类型能找到对应的bean,所以Spring容器中要存在SqlSessionFactory类型的bean或者SqlSessionTemplate类型的bean。
  • 12)如果你定义的是一个SqlSessionFactory类型的bean,那么最终也会被包装为一个SqlSessionTemplate对象,并且赋值给sqlSession属性
  • 13)而在SqlSessionTemplate类中就存在一个getMapper方法,这个方法中就产生一个Mapper接口代理对象
  • 14)到时候,当执行该代理对象的某个方法时,就会进入到Mybatis框架的底层执行流程

这里注意:SpringManagedTransaction是由SqlSessionFactoryBean引入的。

分析一下Mapper代理对象执行查询,比如userMapper.selectById(),其底层调用的是啥?

  • 其实调用的是SqlSessionTemplate.selectOne,主要是为了线程安全的,则每个线程都会获取不同的DefaultSqlSession;如果是事务,同一个线程会通过ThreadLocal存储获取同一个DefaultSqlSession(如果不是事务,同一个线程执行不同的sql语句也会获取不同的DefaultSqlSession,这样会导致一级缓存失效。一级缓存生效的前提是:同一个DefaultSqlSession执行多个相同的sql语句)
  • SqlSessionTemplate会调用到SqlSessionProxy.selectOne,SqlSessionProxy的InvocationHandler是SqlSessionInterceptor,在SqlSessionInterceptor#invoke()里面会getSqlSession()返回一个SqlSession(这里返回的就是DefaultSqlSession)
  • SqlSessionProxy会调用至DefaultSqlSession.selectOne 线程不安全的

一级缓存失效问题:

  • 一般不使用一级缓存,跟事务隔离级别会冲突。比如读已提交想要读取到不同结果,但是使用缓存后,读取到的每次都一样。

Mybatis-Spring 2.0.6版本底层源码执行流程

核心区别:Mybatis-Spring 1.3.2在MapperScannerRegistrar#registerBeanDefinitions就会去扫描Mapper接口并生成BD注册到Sprign容器。而Mybatis-Spring 2.0.6在MapperScannerRegistrar#registerBeanDefinitions只是注册了一个新的BD:MapperScannerConfigurer,扫描逻辑放到了这个类中,因为这个类是一个BeanDefinitionRegistryPostProcessor。

  • 1)通过@MapperScan导入了MapperScannerRegistrar类
  • 2)MapperScannerRegistrar类实现了ImportBeanDefinitionRegistrar接口,所以Spring在启动时会调用MapperScannerRegistrar类中的registerBeanDefinitions方法
  • 3)在registerBeanDefinitions方法中注册一个MapperScannerConfigurer类型的BeanDefinition
  • 4)而MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor接口,所以Spring在启动过程中时会调用它的postProcessBeanDefinitionRegistry()方法
  • 5)在postProcessBeanDefinitionRegistry方法中会生成一个ClassPathMapperScanner对象,然后进行扫描
  • 6)后续的逻辑和1.3.2版本一样。

invokeBeanFactoryPostProcessors()中整合Mybatis的地方

invokeBeanFactoryPostProcessors()执行流程:

  • 1)执行通过ApplicationContext手动添加进来的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 2)执行BeanFactory中实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法。这里会将ConfigurationClassPostProcessor的BeanDefinition实例化出来,并进行调用。这里会处理MapperScannerRegistrar,是个ImportBeanDefinitionRegistrar。Mybatis-Spring 1.3.2直接在这里扫描,Mybatis-Spring 2.0.6新引入了一个BeanDefinitionRegistryPostProcessor:MapperScannerConfigurer。
  • 3)执行BeanFactory中实现了Ordered接口的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法
  • 4)执行BeanFactory中其他的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法(这里是个循环,如果新注册了BeanDefinitionRegistryPostProcessor,会继续循环进行处理)。Mybatis-Spring
    2.0.6的MapperScannerConfigurer会在这里扫描所有Mapper接口并生成BD注册到Spring容器。
  • 5)执行上面所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
  • 6)执行通过ApplicationContext手动添加进来的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 7)执行BeanFactory中实现了PriorityOrdered接口的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 8)执行BeanFactory中实现了Ordered接口的BeanFactoryPostProcessor的postProcessBeanFactory()方法
  • 9)执行BeanFactory中其他的BeanFactoryPostProcessor的postProcessBeanFactory()方法

以上就是Spring整合Mybatis框架源码剖析的详细内容,更多关于Spring整合Mybatis的资料请关注脚本之家其它相关文章!

相关文章

  • springsecurity实现用户登录认证快速使用示例代码(前后端分离项目)

    springsecurity实现用户登录认证快速使用示例代码(前后端分离项目)

    这篇文章主要介绍了springsecurity实现用户登录认证快速使用示例代码(前后端分离项目),本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-03-03
  • Spring Boot 自定义starter的示例代码

    Spring Boot 自定义starter的示例代码

    这篇文章主要介绍了Spring Boot 自定义starter的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • struts2.2.3+spring3.1.0+mybatis3.1.0框架整合集成简单demo

    struts2.2.3+spring3.1.0+mybatis3.1.0框架整合集成简单demo

    本篇文章主要介绍了struts2.2.3+spring3.1.0 + mybatis3.1.0框架整合,结合在一起实现用户的增删改查功能,有需要的可以了解一下。
    2016-11-11
  • 深入了解Java方法的重载与重写

    深入了解Java方法的重载与重写

    在最初学习java的时候,人们都知道,java这种面向对象的语言,一共有三大特征,分别是:封装、继承、多态。多态的实现途径有三种:重写、重载、接口实现。本文就来为大家详细讲讲Java方法的重载与重写
    2022-07-07
  • springboot 使用yml配置文件自定义属性的操作代码

    springboot 使用yml配置文件自定义属性的操作代码

    在SpringBoot中yml/yaml文件可以自定义一些属性,以供注入给自定义bean对象的属性,主要通过空格和层次来实现,类似于python代码,本文通过实例代码给大家介绍springboot 使用yml配置文件自定义属性,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • 关于@ComponentScan TypeFilter自定义指定扫描bean的规则

    关于@ComponentScan TypeFilter自定义指定扫描bean的规则

    这篇文章主要介绍了关于@ComponentScan TypeFilter自定义指定扫描bean的规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • mybatis-plus如何修改日志只打印SQL语句不打印查询结果

    mybatis-plus如何修改日志只打印SQL语句不打印查询结果

    这篇文章主要介绍了mybatis-plus如何修改日志只打印SQL语句不打印查询结果问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • Java出现中文乱码问题分析及解决方案

    Java出现中文乱码问题分析及解决方案

    在Java开发中,处理中文乱码是一个常见的问题,由于字符集和编码的复杂性,开发者可能面临各种导致乱码的情况,正确地处理中文字符集对于确保应用程序的可靠性和国际化至关重要,本文给大家介绍了Java中文乱码分析及解决方案,需要的朋友可以参考下
    2024-02-02
  • 浅谈Spring Bean的基本配置

    浅谈Spring Bean的基本配置

    这篇文章主要介绍了浅谈Spring Bean的基本配置,文中有非常详细的代码示例,对正在学习java Spring的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-05-05
  • 解决阿里云OSS使用URL无法访问图片的两种方法

    解决阿里云OSS使用URL无法访问图片的两种方法

    这篇文章主要介绍了解决阿里云OSS使用URL无法访问图片的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08

最新评论