前言:本文主要基于springboot项目,从springboot的拓展角度来分析mybatis是如何与springboot集成的。

1、首先搭建springboot集成mybatis环境

1.1、maven pom文件依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>imalvisc-parent</artifactId><groupId>com.imalvisc</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>spring-mybatis</artifactId><dependencies><!-- lombok插件 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- MySQL数据库 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- Druid数据源 --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><!-- Mybatis SpringBoot组件 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency></dependencies></project>

1.2、application.yml配置文件

###服务器配置
server:port: 9001spring:application:name: user###druid数据源配置datasource:name: dataSourcetype: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/imalvisc?useSSL=falseusername: rootpassword: imalviscdruid:initial-size: 5min-idle: 5max-active: 20max-wait: 60000time-between-eviction-runs-millis: 60000min-evictable-idle-time-millis: 300000validation-query: select 1 from dualtest-while-idle: truetest-on-borrow: falsetest-on-return: falsepool-prepared-statements: truemax-open-prepared-statements: 50max-pool-prepared-statement-per-connection-size: 20filters: stat,wallconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000###mybatis数据源配置
mybatis:type-aliases-package: com.imalvisc.spring.mybatis.modelconfiguration:map-underscore-to-camel-case: true

1.3、application启动类

package com.imalvisc.spring.mybatis;import com.imalvisc.spring.mybatis.mapper.UserInfoMapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
@MapperScan(basePackages = {"com.imalvisc.spring.mybatis.mapper"})
public class Application {public static void main(String[] args) {ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);UserInfoMapper userInfoMapper = applicationContext.getBean(UserInfoMapper.class);System.out.println(userInfoMapper.selectAll());}}

1.4、启动测试

以上就已经将springboot集成mybatis环境搭建完成。下面进行集成原理的解读。

2、springboot集成mybatis原理解读

2.1、在项目中引入了mybatis-spring-boot-starter依赖,mybatis-spring-boot-starter又引进了mybatis-spring-boot-autoconfigure依赖,在mybatis-spring-boot-autoconfigure的类路径下,可以看到META-INF目录下有一个spring.factories文件,文件里面的内容是org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration,这里的意思是springboot项目加载时,会扫描项目本身以及jar包类路径下的META-INF目录的spring.factories文件,然后会加载执行文件里面所配置到的类,同时这就是springboot自动配置的真谛所在。

2.2、查看MybatisAutoConfiguration类发现,这是一个Configuration类,@AutoConfigureAfter(DataSourceAutoConfiguration.class)代表在DataSourceAutoConfiguration类加载完后再加载,这里是因为mybatis环境需要依赖数据源配置,所以必须在数据源配置完成后才进行mybatis配置。在MybatisAutoConfiguration类中,配置了SqlSessionFactory类,所在到这里mybatis的环境就已经生效了。

  @Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setVfs(SpringBootVFS.class);if (StringUtils.hasText(this.properties.getConfigLocation())) {factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));}applyConfiguration(factory);if (this.properties.getConfigurationProperties() != null) {factory.setConfigurationProperties(this.properties.getConfigurationProperties());}if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors);}if (this.databaseIdProvider != null) {factory.setDatabaseIdProvider(this.databaseIdProvider);}if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());}if (this.properties.getTypeAliasesSuperType() != null) {factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());}if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {factory.setMapperLocations(this.properties.resolveMapperLocations());}

2.3、SqlSessionFactory配置完成后,剩下的就是扫描mapper接口并生成代理类存放到IOC容器中,这样就可以依赖注入Mapper了。

2.4、在Application启动类中,加上了@MapperScan(basePackages = {"com.imalvisc.spring.mybatis.mapper"})注解,打开MapperScan注解可以发现,MapperScan加上另一个注解@Import(MapperScannerRegistrar.class),@Import注解这里简单说明下其作用是spring环境监测到@Import注解时,会加载其指定的配置类,具体详细作用可以另查阅资料。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {

2.5、查看MapperScannerRegistrar发现,其实现了ImportBeanDefinitionRegistrar接口,该接口的作用是spring会调用实现该接口的registerBeanDefinitions方法,传入AnnotationMetadata和BeanDefinitionRegistry两个参数,AnnotationMetadata的作用是封装了加上@Import注解的注解的属性,这里解析的可能有点绕口,举例说明就是@MapperScan注解加上了@Import注解,@MapperScan有一个basePackages属性,所以AnnotationMetadata封装了@MapperScan注解的basePackages属性的值。

2.6、MapperScannerRegistrar的registerBeanDefinitions方法中,获取了@MapperScan注解的属性后,调用了自身的重载registerBeanDefinitions方法,重载registerBeanDefinitions方法通过调用ClassPathMapperScanner的doScan方法就完成了Mapper的扫描并加入到spring容器中,到了这里整个mybatis的环境就完全生效了。doScan方法里面的深入逻辑这里就不展开了,需要继续深入剖析的同学可以另查阅资料。

  @Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));if (mapperScanAttrs != null) {registerBeanDefinitions(mapperScanAttrs, registry);}}void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);// this check is needed in Spring 3.1Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");if (!Annotation.class.equals(annotationClass)) {scanner.setAnnotationClass(annotationClass);}Class<?> markerInterface = annoAttrs.getClass("markerInterface");if (!Class.class.equals(markerInterface)) {scanner.setMarkerInterface(markerInterface);}Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");if (!BeanNameGenerator.class.equals(generatorClass)) {scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));}Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {scanner.setMapperFactoryBeanClass(mapperFactoryBeanClass);}scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));List<String> basePackages = new ArrayList<>();basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));scanner.registerFilters();scanner.doScan(StringUtils.toStringArray(basePackages));}

结语:mybatis集成到springboot中,主要是基于两大核心特性,一是springboot的自动配置特性,在路径下的META-INF目录的spring.factories文件配置需要加载的类,二是利用spring的@Import的ImportBeanDefinitionRegistrar特性,根据注解上指定的属性来加载配置。其实其它的技术(如Redis、RabbitMQ、JPA、Swagger等等)通过自动配置的方法集成到springboot环境中,基本都是通过这两种特性来实现,所以希望本文章不仅仅是帮助到同学们理解springboot集成mybatis的原理,更多的希望同学们可以理解springboot环境的拓展思路,以后写出更加优雅springboot拓展代码。

springboot集成mybatis原理剖析相关推荐

  1. Springboot 集成 mybatis 开启二级缓存(redis)

    首先来了解下mybatis 缓存,mybatis缓存分为一级缓存和二级缓存.一级缓存是默认开启的,无需其他配置操作,二级缓存则需要手动设置开启. 一级缓存原理: Mybatis的一级缓存是指同一个Sq ...

  2. BindingException: Invalid bound statement (not found)问题排查:SpringBoot集成Mybatis重点分析...

    重构代码,方法抛出异常:BindingException: Invalid bound statement (not found) 提示信息很明显:mybatis没有提供某方法 先不解释问题原因和排查 ...

  3. java整合mybatis,springboot集成mybatis

    # springboot集成mybatis springboot基础mybatis还是很简单的,比之前springmvc集成mybatis要少很多配置,只要大家按照步骤一步一步来,几分钟就 能实现.具 ...

  4. springboot集成mybatis源码分析-mybatis的mapper执行查询时的流程(三)

    springboot集成mybatis源码分析-mybatis的mapper执行查询时的流程(三) 例: package com.example.demo.service;import com.exa ...

  5. springboot集成mybatis源码分析-启动加载mybatis过程(二)

    springboot集成mybatis源码分析-启动加载mybatis过程(二) 1.springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplicati ...

  6. springboot集成mybatis源码分析(一)

    springboot集成mybatis源码分析(一) 本篇文章只是简单接受使用,具体源码解析请看后续文章 1.新建springboot项目,并导入mybatis的pom配置 配置数据库驱动和mybat ...

  7. SpringBoot集成Mybatis用法笔记

    今天给大家整理SpringBoot集成Mybatis用法笔记.希望对大家能有所帮助! 搭建一个SpringBoot基础项目. 具体可以参考SpringBoot:搭建第一个Web程序 引入相关依赖 &l ...

  8. Java 捕获 mybatis异常_3 springboot集成mybatis和全局异常捕获

    mybatis有两种方式,一种是基于XML,一种是基于注解 springboot集成mybatis 首先先创建表,这里都简化了 DROP TABLE IF EXISTS `user`; CREATE ...

  9. Springboot集成mybatis通用Mapper与分页插件PageHelper

    Springboot集成mybatis通用Mapper与分页插件PageHelper 插件介绍 通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及 ...

最新文章

  1. /D _WINDOWS, /D _CONSOLE
  2. “光名字就想了一年”,苹果三位高管谈M1芯片
  3. VS Code 1.29 发布,众多新功能有没有你想要的?
  4. Opencv3编程入门学习笔记(四)之split通道分离Debug过程中0xC0000005内存访问冲突问题
  5. rabbitmq简单运用
  6. 易到用车提现再度被延期?!声明:因贾跃亭所欠债务导致
  7. 虚拟化顶级技术会议KVM Forum演讲分享 | 移动云KVM共享云盘技术实践
  8. 131. 分割回文串
  9. [转载] python字符串表示方法_python字符串使用方法归纳
  10. Oracle 初始化参数性能视图
  11. 如何把鼠标宏用c语言写出来,鼠标宏怎么设置,手把手教你鼠标如何设置宏
  12. 2022考研数据结构_1 绪论
  13. 计算机所建造全过程,Midas桥梁建模计算,全过程图文解析!
  14. WinHex自定义模板
  15. 马蹄集------函数的幂
  16. 解决Outlook搜索功能的搜索结果不完整问题
  17. PyQt5 打造GUI爬虫 小说下载器
  18. Servlet的三个名字
  19. pythonmd5解密代码_python写一个md5解密器示例,pythonmd5解密器
  20. 优化DNS,加快DNS的解析速度

热门文章

  1. html中prependid的作用,jQuery中append(),prepend()与after(),before()的区别
  2. 粮食大篷车 首进宁波郎官社区 当年新米受欢迎
  3. F - 奶牛晒衣服(二分)
  4. 有这五款团队协作工具,企业不用再担心团队协作效率低!
  5. 网络信息安全攻防学习平台 上传,解密通关writeup
  6. 地理坐标系与投影坐标系WKID查询
  7. PHP小旋风站群系统源码
  8. SnapGene 6.0.2 完美简体 不闪退
  9. Elsevier发表文章要求
  10. SpringBoot实现文件上传(头像)