Spring和Mybatis整合的原理详解

目录
  • 前言
  • 简单猜想
  • 案例搭建
  • 通过扫描接口
  • 正式开始
    • setBeanName
    • setApplicationContext
    • afterProperties
    • postProcessBeanDefinitionRegistry
  • 总结

前言

最近读完了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 {

这个类继承了几个接口:

  • BeanDefinitionRegistryPostProcessor
  • 这个接口追进去,发现该接口继承自BeanFactoryPostProcessor,也就相当于spring在refresh方法中有一个方法专门去执行这类的接口。
  • InitializingBean
  • 在createBean的生命周期中会调用该接口的afterProperties方法。
  • ApplicationContextAware
  • Spring在创建该Bean时会调用setapplicationContext方法注入上下文
  • BeanNameAware
  • 创建是调用setBeanName方法

按照这样的一个接口被执行的顺序是,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整合内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot整合mybatis开启二级缓存的实现示例

    目录 前言 mybatis 一级缓存和二级缓存的概念 pom引入依赖 application.properties 文件配置 mapper.xml 文件配置 cache-ref 完整示例代码 踩坑 参考资料 前言 下面大部分内容来源于网上的相关帖子和官网,自己简单写了个demo体验了下,个人感觉mybatis的缓存并不是很合适 查询做缓存时,遇到更新操作就会刷新缓存,尤其是多表查询时,就会很难控制.对于那些需要缓存的热数据应该抽出来放到redis上做. mybatis 一级缓存和二级缓存的概念

  • SpringBoot整合Mybatis-plus的具体过程使用

    目录 1.MyBatisX插件 2.引入依赖 3.编写配置 4.编写接口 5.运行测试 6.完整代码 1.MyBatisX插件 在使用mybatis或者mybatis-plus时,我们可以安装IDEA的MyBatis的插件 - MyBatisX, 这样我们就可以实现点击接口跳转到sql文件, 点击sql文件可以跳转到接口的功能, 很方便.这个插件的功能还有很多, 可以查看MyBatis-Plus官网 安装方法:打开 IDEA,进入 File -> Settings -> Plugins -&g

  • SpringBoot MyBatis保姆级整合教程

    目录 Spring Boot整合MyBatis 数据准备 创建项目引入相应的启动器 编写与数据库表 编写配置文件 注解方式整合Mybatis 配置文件的方式整合MyBatis 创建接口类 创建XML映射文件 配置XML映射文件路径 编写单元测试进行接口方法测试 Spring Boot整合MyBatis MyBatis 是一款优秀的持久层框架,Spring Boot官方虽然没有对MyBatis进行整合,但是MyBatis团队自行适配了对应的启动器,进一步简化了使用MyBatis进行数据的操作 基础

  • springboot整合mybatis的超详细过程(配置模式+注解模式)

    目录 一.简单介绍 二具体配置 2.1.配置相关的依赖. 2.2 写.mapper.controller.service 2.2.1mapper文件 2.2.2service文件 2.2.2controller文件 2.3配置相关文件 三.结果截图 四.可能遇到的报错 一.简单介绍 1.配置相关的依赖2.配置模式3写.mapper.controller.service4.配置yaml文件 配置mybatis全局配置文件(这里我使用的是配置模式+注解模式所以需要配置全局文件) 二具体配置 2.1.

  • Mybatis插件扩展及与Spring整合原理分析

    前言 前面几篇文章分析了Mybatis的核心原理,但模块较多,没有一一分析,更多的需要读者自己下来研究.不过Mybatis的插件扩展机制还是非常重要的,像PageHelper就是一个扩展插件,熟悉其扩展原理,才能更好的针对我们的业务作出更合适的扩展.另外,现在Mybatis都是和Spring/SpringBoot一起使用,那么Mybatis又是如何与它们进行整合的呢?一切答案尽在本文之中. 正文 插件扩展 1. Interceptor核心实现原理 熟悉Mybatis配置的都知道,在xml配置中我

  • Spring整合Mybatis实操分享

    目录 Mybatis的基本工作原理 分析需要解决的问题 Spring中Bean的产生过程 解决问题 总结 在介绍Spring整合Mybatis原理之前,我们得先来稍微介绍Mybatis的工作原理. Mybatis的基本工作原理 在Mybatis中,我们可以使用一个接口去定义要执行sql,简化代码如下: 定义一个接口,@Select表示要执行查询sql语句. public interface UserMapper { @Select("select * from user where id = #

  • Spring利用注解整合Mybatis的方法详解

    目录 一.环境准备 步骤1:数据库相关 步骤2:导入jar包 步骤3:创建模型类 步骤4:创建Dao接口和实现类 步骤5:创建Service接口和实现类 步骤6:添加jdbc.properties文件 步骤7:添加Mybatis核心配置文件 步骤8:编写测试程序 二.整合思路分析 三.整合步骤 步骤1:导入整合jar包 步骤2:创建数据源配置类 步骤3:创建Mybatis配置类 步骤4:创建Spring主配置类 步骤5:编写运行程序 一.环境准备 步骤1:数据库相关 建库建表 创建spring_

  • SpringBoot整合MyBatis-Plus乐观锁不生效的问题及解决方法

    目录 SpringBoot整合Myabtis-Plus 1.依赖导入 2.数据库插入 3.SpringBoot各个层次的操作 3.1.实体类 3.2.configuration 3.2.1.TableField的insert与update 3.2.2.乐观锁配置 3.3.mapper层 3.4.service层 4.控制层测试 4.1.查询所有 4.2.根据id修改信息 SpringBoot整合Myabtis-Plus 在与官网配置一致的情况下依旧无法生效,如下整合mybatis-plus 1.

  • Spring和Mybatis整合的原理详解

    目录 前言 简单猜想 案例搭建 通过扫描接口 正式开始 setBeanName setApplicationContext afterProperties postProcessBeanDefinitionRegistry 总结 前言 最近读完了Spring的IOC部分的源码,受益匪浅,这篇文章讲解一下MyBatis是如何做到与Spring整合的.MyBatis是如何做到干扰Spring的生命周期,把Mapper一个个的注册到Spring容器中的将在这里揭秘. 简单猜想 因为阅读过Spring源

  • spring事务Propagation及其实现原理详解

    本文研究的主要是spring事务Propagation及其实现原理,具体介绍如下. 简介 spring目前已是java开发的一个事实标准,这得益于它的便利.功能齐全.容易上手等特性.在开发过程当中,操作DB是非常常见的操作,而涉及到db,就会涉及到事务.事务在平时的开发过程当中,就算没有注意到,程序正常执行不会有副作用,但如果出现了异常,而又没有处理好事务的话,可能就会出现意想不到的结果.spring在事务方面进行了各种操作的封装,特别是声明式事务的出现,让开发变得更加的舒心.spring对事务

  • Java MyBatis本地缓存原理详解

    目录 背景 发现问题 复现 解决问题 探究缓存的原理 Sql查询部分深入 初见缓存 告一段落 番外篇-Myabtis创建CacheKey的算法. 构造方法 结束语 背景 出现了一次生产事故,事情是这样的,我们有一个项目,Java访问数据库的框架使用的是MyBatis.然后一个业务员在系统中查询了一个订单,发现这个订单是未支付的状态,于是业务员联系客户,让客户支付,客户支付完成后,业务员又去系统查询,结果还是未支付状态,刷新了页面也是一样,不过过了一会就好了.业务员把这个延迟问题,反馈给了我们.我

  • Spring框架IOC容器底层原理详解

    目录 1.什么是IOC 2.IOC容器的底层原理 3.那么上边提到的三种技术如何实现IOC的呢 4.IOC(接口) 1.什么是IOC IOC – Inverse of Control,控制反转,将对象的创建权力反转给Spring框架! 在java当中一个类想要使用另一个类的方法,就必须在这个类当中创建这个类的对象,那么可能会出现如下情况, 比如A类当中创建着B对象,B类当中有C对象,C类当中有A对象,这个如果一个类出了问题,那么可能会导致这个框架出现问题. Spring 将创建对象的权利给了IO

  • SpringMVC mybatis整合实例代码详解

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis . 一.逆向工程生成基础信息 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis G

  • Spring Boot Actuator执行器运行原理详解

    Spring Boot执行器(Actuator)提供安全端点,用于监视和管理Spring Boot应用程序. 默认情况下,所有执行器端点都是安全的. 在本章中,将详细了解如何为应用程序启用Spring Boot执行器. 启用Spring Boot Actuator 要为Spring Boot应用程序启用Spring Boot执行器端点,需要在构建配置文件中添加Spring Boot Starter执行器依赖项. Maven用户可以在pom.xml 文件中添加以下依赖项. <dependency>

  • Spring MVC数据绑定概述及原理详解

    数据绑定概述 在执行程序时,Spring MVC根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中. 这种将请求消息数据与后台方法参数建立连接的过程就是 Spring MVC中的数据绑定. 在数据绑定过程中,Spring MVC框架会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数.具体的信息处理过程的步骤如下. (1)Spring MVC将

  • JAVA Spring Boot 自动配置实现原理详解

    目录 引言 主启动类的注解@SpringBootApplication 1.@SpringBootConfiguration 2.@ComponentScan 3.@EnableAutoConfiguration 3.1.@AutoConfigurationPackage 3.2.@Import({AutoConfigurationImportSelector.class}) spring-boot-autoconfigure中的默认配置类 配置数据的绑定 总结 引言 在使用ssm框架的时候,每

  • Spring security BCryptPasswordEncoder密码验证原理详解

    一.加密算法和hash算法的区别 加密算法是一种可逆的算法,基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为"密文",但在用相应的密钥进行操作之后就可以得到原来的内容 . 哈希算法是一种不可逆的算法,是把任意长度的输入通过散列算法变换成固定长度的输出,输出就是散列值,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值. 二.源码解析 BCryptPasswordEncoder类实现了PasswordEncoder接口,这个接口中定义

  • Spring和MyBatis整合自动生成代码里面text类型遇到的坑

    Spring和MyBatis整合以后,使用自动生成代码工具生成dao和mapper配置文件,生成步骤如下(以Intelli idea为例). 1.编写生成代码配置文件generatorConfig.xml. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator

随机推荐