第三节 mybatis-spring-boot-starter 案例分析

news2024/9/22 4:08:07

tips:可以利用 docker-desktop 快速搭建 MySQL、Redis 等中间件Docker 安装 Redis | 菜鸟教程

上一章,我们完成了一个自定义 Starter ; 这一章,我们来看看 Mybatis 是如何使用 Starter,通过学习 mybatis-spring-boot-starter 进一步学习 Starter。

本章代码地址:uzong-starter-learning: 学习 SpringBoot Starter 的工程案例

一、Starter 的应用

1.1 “老一代”程序员离不开的 SSM

在没有 SpringBoot 之前,搭建一个 SSM 是我们“老一代”Java 程序员入门一定会干的事情。因为找不到配置文件而反复尝试的挫败感,依然历历在目; 但 SpringBoot 横空出世以后;就解决了大量繁琐的配置,让搭建过程变得异常简单。

1.2 项目需求

接下来, 实现从 mysql 中读取数据的案例; 该案例也就是每天 CRUD 的缩影。

1.3 技术选型

为了简化 Spring、SpringMVC 的搭建以及部署 tomcat 的过程

基础框架依然选择 SpringBoot。但一个使用 mybatis-spring-boot-starter,一个使用最原始的 mybatis ,实现 ORM 。

使用 Starter

不使用 Starter

mybatis-spring-boot-starter

最原始的 mybatis

对应的两个源码 module

演绎 mybatis 从无 Starter 到有 Starter 的变化,感受一下使用 Starter 的好处。

二、代码比较

2.1 项目工程

为了简化,各层传输,直接用 DO,没有使用 DTO、VO 等。 注意:它是不规范的。代码如下所示:

  1. controller
  2. service
  3. mapper(dao)

启动应用,并访问。实现从数据库读取数据的效果,如下所示:http://localhost:8080/api/users/1

那么使用 Mybatis Starter 和 不使用 Mybatis 的对比差异

2.2 使用 Starter 的

第一步 引入 maven 依赖

 <dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>

        <!-- MyBatis Starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.3</version>
        </dependency>

        <!-- MySQL Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
    </dependencies>

仅仅 Spring Boot Starter Web、MyBatis Starter和MySQL Connector的依赖

maven 依赖

描述

spring-boot-starter-web

web 所必须的 jar

mybatis-spring-boot-starter

mybatis orm 核心

mysql-connector-java

驱动

实现一个 CRUD,只需要使用三个 maven 依赖就可以。当我们刚开始学习 Spring web 项目的时候,需要引入大量的 maven 依赖,而且还容易出现依赖之间的版本不兼容。

Starter 的引入,使得功能更加内聚; 减少了上手成本。

第二步 编写 Mapper、Service、Controller 类

创建一个MyBatis Mapper接口。(可以选择使用 XML 映射文件而不是在 Mapper 接口中使用注解)

@Mapper
public interface UserMapper {

    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(Long id);

    @Select("SELECT * FROM user")
    List<User> getAllUsers();
}

创建一个服务类来处理业务逻辑

@Service
public class UserService {

    @Resource
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.getUserById(id);
    }

    public List<User> getAllUsers() {
        return userMapper.getAllUsers();
    }
}

创建Controller以将数据公开为REST API

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Resource
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
}

第三步 创建一个主类, 并启动Spring Boot应用

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

一个简单 restful api 开发就这么轻松就完成了。将 mybatis-spring-boot-starter 换成原生的 mybatis 依赖

2.3 不使用 Starter

具体代码,可以参考:mybatis-without-starter 模块

引入 maven ,这一步与使用 Starter 时最明显的区别

<dependencies>
        <!-- Spring Boot Starter Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!-- MyBatis Spring integration -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- Spring Boot Starter JDBC for DataSource configuration -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-b`oot-starter-jdbc</artifactId>
            <version>1.5.19.RELEASE</version>
        </dependency>

        <!-- MySQL Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
    </dependencies>

第二步:Mapper、Service、Controller 类与使用 Starter 一致。

第三步:除此以外,还行编写一个 Config,用于扫描 mapper 文件,以及添加 SqlSessionFactory bean

@Configuration
@MapperScan("com.uzong.instance2.mapper")
public class MyBatisConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        return sessionFactory.getObject();
    }
}

如果没有 MyBatisConfig 这个配置类,将无法启动。

第四步:编写启动类并启动,略。

2.4 两者差异对比

对比项

Starter

无Starter

依赖

简单的依赖

配置类

不需要

增加 MyBatisConfig 配置,添加 SqlSessionFactory bean 并通过 @MapperScan 扫描生成 MapperFactoryBean

依赖版本管理

不考虑

各依赖之间的版管理,如果版本不匹配,容易导致 classNotFoundException、NoClassDefFoundError、NoSuchMethodError 等问题

额外补充:常常因为多个依赖一起引入,导致版本不匹配,出现一些问题。比如下面是方法找不到的错误情况

java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.isCandidateClass(Ljava/lang/Class;Ljava/lang/Class;)Z

2.5 Starter 优势

通过对比,不难发现, Starter 可有很多不错的优点。

Starter 将麻烦留给自己,把简单留给使用者

三、探索 Starter 都做了什么

那么 mybatis-spring-boot-starter 到底都做了什么呢?接下来分析一下其结构

3.1 maven 依赖管理

分析 mybatis-spring-boot-starter 依赖

通过 maven 依赖,mybatis-spring-boot-starter 引入了 maven 依赖和我们单独引入 mybatis 的方式是一致的。

Starter 能将所需要的依赖打包集成。

与 mybatis 单独引入不同, mybatis-spring-boot-starter 依赖包还有一个不一样的依赖 mybatis-spring-boot-autoconfigure, 它也是 Starter 不用手动编写配置类的原因。

3.2 mybatis-spring-boot-starter 源码

下载 mybatis-spring-boot-starter 源码。

地址: GitHub - mybatis/spring-boot-starter: MyBatis integration with Spring Boot 分支选择 1.3x,保证所选版本一致。

上面是 mybatis-spring-boot-starter(核心:mybatis-spring-boot-autoconfigure)的结构。

核心类org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

主要作用:

  • 注入SqlSessionFactory、SqlSessionTemplate 等核心 bean,这是 Mybatis 核心的类。
  • 提供 AutoConfiguredMapperScannerRegistrar 的注入,用于将带有 @Mapper 的接口生成代理类。

MybatisAutoConfiguration代码分析

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      .......
      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
      if (this.resourceLoader != null) {
        scanner.setResourceLoader(this.resourceLoader);
      }

      // org.apache.ibatis.annotations.Mapper 设置扫描的注解
      scanner.setAnnotationClass(Mapper.class);
      scanner.registerFilters();
      scanner.doScan(StringUtils.toStringArray(packages));

    }

核心处理逻辑:

org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions:

设置 sqlSessionFactory 等属性, 根据 Mapper 接口生成 MapperFactoryBean 代理对象。

将 @Mapper 接口类生成 MapperFactoryBean。

MybatisAutoConfiguration 的功能:和不使用 Starter 中的 com.uzong.instance2.config.MyBatisConfig 是相似的,如下所示:

  1. 生成必须的 Bean,例如:SqlSessionFactory
  2. 通过代理生成 MapperFactoryBean

Starter 的关键点:

  • xxxAutoConfiguration: 注入 bean
  • xxxProperties: 提供动态参数配置 (非必须)
  • spring.factories: 用于 SPI 引导

3.3 Starter 理解

mybatis-spring-boot-starter 代码并不复杂,发挥主要作用的还是 mybatis、mybatis-spring 原始包中的核心类。

而 Starter 的作用,像一个皮条客,提供了一个场子,把各个核心功能通过合理的手段整合到一起,包装成对外提供价值的服务。

Starter 是简单的,它只需要简单地遵循一点规范即可,现在看来并没有太多的东西。

补充:MybatisAutoConfiguration 中有一些条件注解,比如 @ConditionalOnMissingBean ,我们将会在单独的章节进行讲解。

四、本章小结

本章内容,通过两个案例,讲解 mybatis-spring-boot-starter 的使用对比。 通过使用和没有使用,在项目里面的对比来认识 Starter, Starter 并不复杂,但是它的出现却能提供不少的便利。

但是复杂并不是真正减少,只是被转移了。现在我们只看到了简单的部分,复杂的原理部分还没有被看到呢。

下面一个章,我们将开始详细讲解 Starter 的运行过程和源码理解。彻彻底底明白 SpringBoot Starter 将复杂留个自己,把简单留个别人的原因。

已同步发布到公众号:面汤放盐  第三节 mybatis-spring-boot-starter 案例分析 (qq.com)

掘金账号:第三节 mybatis-spring-boot-starter 案例分析 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1685267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习模型keras第二十二讲:使用KerasCV进行语义分割

1、语义分割的概念 1.1语义分割的定义 语义分割是一种计算机视觉领域的图像分割技术&#xff0c;其目标是将一张图像中的每个像素分配给预定义的类别。 在图像领域&#xff0c;语义指的是对图像意思的理解。语义分割就是按照“语义”给图像上目标类别中的每一点打上一个标签…

C#屏蔽基类成员

可以用与积累成员名称相同的成员来屏蔽 要让编译器知道你在故意屏蔽继承的成员&#xff0c;可以用new修饰符。否则程序可以成功编译&#xff0c;但是编译器会警告你隐藏了一个继承的成员 using System;class someClass {public string F1 "Someclass F1";public v…

第四节 Starter 加载时机和源码理解

tips&#xff1a;每个 springBoot 的版本不同&#xff0c;代码的实现存会存在不同。 上一章&#xff0c;我们聊到 mybatis-spring-boot-starter&#xff1b; 简单分析了它的结构。 这一章我们将着重分析 Starter 的加载机制&#xff0c;并结合源码进行分析理解。 一、加载实际…

若依解决使用https上传文件返回http路径问题

若依通过HTTPS请求进行文件上传时却返回HTTP的文件链接地址&#xff0c;主要原因是使用了 request.getRequestURL 获取链接地址。 解决办法&#xff1a; 在nginx配置文件location处加上&#xff1a;proxy_set_header X-Forwarded-Scheme $scheme; 然后代码通过request.getHea…

在程序运行中动态改变变量

场景 出于测试目的&#xff0c;需要在程序运行中去改变程序中的参数 思路 动态的去读第三方存储&#xff0c;比如数据库&#xff0c;缓存&#xff0c;甚至是文件 我的实现 这里使用了gflags&#xff0c;通过flaks实现一个api提供flag的修改 Gflags 是 Google 内部使用的命…

人工智能(Educoder)-- 机器学习 -- 神经网络(初级)

第一关 注&#xff1a; 神经网络的起源和应用 起源&#xff1a;神经网络最早由心理学家和神经学家开创&#xff0c;目的是模拟生物神经系统对真实世界物体的交互反应。应用&#xff1a;现代神经网络用于分类&#xff08;如图像识别、文本分类&#xff09;和数值预测&#xff08…

docker启动clickhouse

docker启动clickhouse 创建clickhouse目录拉取镜像启动临时容器, 生成配置文件正式启动 clickhouse越来越流行&#xff0c;本地想安装个测试环境 创建clickhouse目录 后续作为挂载卷使用 mkdir -p /home/gugu/ckdata/data mkdir -p /home/gugu/ckdata/conf mkdir -p /home/gu…

信捷XD系列PLC通讯失败程序无法下载如何设置

如题:最近在使用信捷PLC&#xff0c;有时会出现通讯不上的问题&#xff0c;下面将通讯配置步骤及注意事项分享。 一、确保PLC通电&#xff0c;电脑使用USB通讯线和PLC连接。 二、打开程序&#xff0c;点击串口标识&#xff0c;会弹出通信配置窗口。 三、双击USB通讯这条进行设…

【Python小案例】Python+mysql+PyQt5健康体检报告查询

下载安装Python3.7.8 python官网&#xff1a;https://www.python.org/ PyQt5配置 安装PyQt5 pip install PyQt5pip install qt5_toolspytcharm创建项目 配置外部工具 QTDesigner的Arguments语句不用填 QTDesigner的Working directory语句:$ProjectFileDir$ Pyuic的Argume…

【GDAL】GDAL库学习(C#版本)

1.GDAL 2.VS2022配置GDAL环境&#xff08;C#&#xff09; VS2022工具–NuGet包管理器–管理解决方案的NuGet程序包&#xff0c;直接安装GDAL包。 并且直接用应用到当前的控制台程序中。 找一张tiff格式的图片&#xff0c;或者用格式转换网站&#xff1a;https://www.zamzar.c…

go升级后 编译的exe在win7上无法正常运行

D:/Go/src/runtime/sys_windows_amd64.s:65 x75 fpx22fca sp-0x22fc8日 升级到go 1.21后报一堆错误&#xff0c;要死了啊 原来是go 1.21不支持win7了&#xff0c;必须把go退回到1.20版本 谷歌发布编程语言 Go 1.21 版本&#xff1a;取消支持微软 Win7/8 及苹果 macOS 10.13/10…

爬虫技术升级:如何结合DrissionPage和Auth代理插件实现数据采集

背景/引言 在大数据时代&#xff0c;网络爬虫技术已经成为数据收集的重要手段之一。爬虫技术可以自动化地从互联网上收集数据&#xff0c;节省大量人力和时间成本。然而&#xff0c;当使用需要身份验证的代理服务器时&#xff0c;许多现有的爬虫框架并不直接支持代理认证。这就…

[力扣]——231.2的幂

题目描述&#xff1a; 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 bool isPowerOfTwo(int n){ if(n0)retur…

vue3结合element-plus之如何优雅的使用表格

背景 表格组件的使用在后台管理系统中是非常常见的,但是如果每次使用表格我们都去一次一次地从 element-plus 官网去 复制、粘贴和修改成自己想要的表格。 这样一来也说得过去,但是如果我们静下来细想不难发现,表格的使用都是大同小异的,每次都去复制粘贴,对于有很多表格…

深度学习之基于YOLOV5的口罩检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着全球公共卫生事件的频发&#xff0c;口罩成为了人们日常生活中不可或缺的一部分。在公共场所&am…

slam14讲(第8讲、前端里程计)LK光流、直接法

直接法的引出 因为第7讲大部分都是讲特征点法&#xff0c;通过提取orb特征点和点的描述子&#xff0c;来构建两帧图像之间的特征点对应关系。这种方法会有缺点&#xff1a; 关键点和描述子提取计算耗时&#xff0c;如果相机的频率高&#xff0c;则slam算法大部分耗时被占。特…

轻量SEO分析报告程序网站已开心去授权

轻量SEO分析报告程序网站已开心去授权&#xff0c;可以让你生成有洞察力的、 简洁的、易于理解的SEO报告&#xff0c;帮助你的网页排名和表现更好 网站源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

算法学习:快速排序

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f680; 引言&#x1f4cc; 快速排序算法核心思想1. 选择基准值&#xff08;Pivot&#xff09;2. 分区操作&#xff08;Partitioning&#xff09;3. 递归排序子序列 &#x1f4cc; JavaScript 实现1. 快速排序主函数2…

OGG几何内核-BRepBuilderAPI_MakeEdge学习

OGG几何内核fork自OCCT 7.7.0&#xff0c; BRepBuilderAPI_MakeEdge是几何内核的一个重要和基础的功能&#xff0c;也十分复杂&#xff0c;因为要支持line、circle、ellipse&#xff0c;parabola&#xff0c;hyperbola&#xff0c;circle&#xff0c;beziercurve&#xff0c;b…

Web前端开发技术-格式化文本 Web页面初步设计

目录 Web页面初步设计 标题字标记 基本语法&#xff1a; 语法说明&#xff1a; 添加空格与特殊符号 基本语法&#xff1a; 语法说明: 特殊字符对应的代码: 代码解释&#xff1a; 格式化文本标记 文本修饰标记 计算机输出标记 字体font标记 基本语法&#xff1a; 属…