Spring整合Mybatis源码分析

开发者 2024-10-1 23:52:17 112 0 来自 中国
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,然后创建对象,但是这里是接口,创建对象会报错,我们这里须要控制对象的生成过程(生成动态署理)
1.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框架的底层实行流程
3.png 这里留意: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 线程不安全的
一级缓存失效标题:

  • 一样平常不利用一级缓存,跟变乱隔离级别会辩说。比如读已提交想要读取到差别效果,但是利用缓存后,读取到的每次都一样。
2.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版本一样。
3.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()方法
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-21 20:18, Processed in 0.140343 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表