文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring和Mybatis整合的原理详解

2024-04-02 19:55

关注

前言

最近读完了Spring的IOC部分的源码,受益匪浅,这篇文章讲解一下MyBatis是如何做到与Spring整合的。MyBatis是如何做到干扰Spring的生命周期,把Mapper一个个的注册到Spring容器中的将在这里揭秘。

简单猜想

因为阅读过Spring源码后对他有了一定的认识,这里可以简单盲猜一下,使用的是什么方式,在上一篇文章揭秘Autowired注解中有介绍到。我们只是向xml中写入了一行<context:annotation-config/>配置。Spring就像BeanFatory中写入了很多的BeanPostProcessor,这里我觉得采用的功能类似。
通过定义spring.handlers文件。然后mybatis定义各种处理标签的Handler和Paser。随后通过读取配置文件中的mappers标签,去像register中注册BeanDefinition,这是其一。

第二种方法就是类似AutowiredAnnotationBeanPostProcessor的实现方式,通过Xml注册一个Bean,这个Bean继承自MergedBeanDefinitionPostProcessor,由于继承自MegedBeanDefinitionPostProcessor所以他会优先Bean运行,在此时可以像Bean工厂中添加BeanDefinition。

其实我们的目标很明确,只要我们能在Spring调用InitiazionBean方法之前去把mapper的BeanDefinition添加进Spring容器,都可以实现当前的目的。

那么接下来我们就看看MyBatis本身究竟是如何实现的吧。

案例搭建

源码地址:MyBatis整合Spring有两种方式,第一种是通过Xml,第二种是通过Mapper接口的扫描,具体的整合方法我这里就不演示了,直接看配置文件吧。其实就是application.xml有一点改动。

通过扫描接口

这里搭建一个最简单的整合方式:

正式开始

通过上方的配置文件,可以看见一个配置了一个叫scannerConfigurer,这里先去看一下这个类。

public class MapperScannerConfigurer
    implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

这个类继承了几个接口:

按照这样的一个接口被执行的顺序是,setBeanName -> setApplicationContext -> afterproperties -> postProcessBeanDefinitionRegistry

setBeanName

@Override
public void setBeanName(String name) {
  this.beanName = name;
}

这个方法很明显不是。

setApplicationContext

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
  this.applicationContext = applicationContext;
}

这个方法很明显,也不是。

afterProperties

@Override
public void afterPropertiesSet() throws Exception {
  notNull(this.basePackage, "Property 'basePackage' is required");
}

这个方法是用来校验的,判断了basePackage是否为空,如果为空就throw Exception。

postProcessBeanDefinitionRegistry

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  if (this.processPropertyPlaceHolders) {
    processPropertyPlaceHolders();
  }

  ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
  scanner.setAddToConfig(this.addToConfig);
  scanner.setAnnotationClass(this.annotationClass);
  scanner.setMarkerInterface(this.markerInterface);
  scanner.setSqlSessionFactory(this.sqlSessionFactory);
  scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
  scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
  scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
  scanner.setResourceLoader(this.applicationContext);
  scanner.setBeanNameGenerator(this.nameGenerator);
  scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
  if (StringUtils.hasText(lazyInitialization)) {
    scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
  }
  if (StringUtils.hasText(defaultScope)) {
    scanner.setDefaultScope(defaultScope);
  }
  scanner.registerFilters();
  scanner.scan(
      StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}

那这里就很明显了,这里创建ClassPathMapperScanner。随后对scanner的一些配置做了一些设置。

然后就调用了registerFilters方法,字面意思也就是注册过滤器,这里就跳过吧,无非是设置一些属性,然后在后面解析的时候判断过滤条件,在循环时continue。

主要是scan方法这里要详细看一下:

public int scan(String... basePackages) {
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    this.doScan(basePackages);
    if (this.includeAnnotationConfig) {
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

    return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
}

这里这个扫描类其实是Spring中的类,ClassPathBeanDefinitionScanner,当中的scan方法。所以这里可能会有点眼熟,类似于创建Bean时,先获取一下创建之前的Bean总数,然后再获取创建之后的Bean总数,返回时减一下就知道这次创建了多少。

总结

其实到这里呢,我们就算是结束了,因为后续的包扫描,在严格意义上来讲是Spring来实现的,我后续开篇文章来讲解这个东西。

这里总结一下,正如我猜想的一样,myBatis只要在finishBeanFactoryInitialization方法之前,把Mapper的BeanDefinition塞进Spring容器中,在最后的finishBeanFactoryInitialization方法,Spring自然就会根据BeanDefinition去创建Bean了。

这里使用的方法是,注册一个BeanFactoryPostProcessor,所以这个方法会在finishBeanFactoryInitialization方法之前运行,所以这里是成功的。

到此这篇关于Spring和Mybatis整合的原理详解的文章就介绍到这了,更多相关Spring和Mybatis整合内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯