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

tips:可以利用 docker-desktop 快速搭建 MySQL、Redis 等中间件www.runoob.com/docker/dock...

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

本章代码地址: https://gitee.com/uzongn/uzong-starter-learning

一、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 依赖

XML 复制代码
 <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 接口中使用注解)

JAVA 复制代码
@Mapper
public interface UserMapper {

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

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

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

JAVA 复制代码
@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

JAVA 复制代码
@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应用

JAVA 复制代码
@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 时最明显的区别

XML 复制代码
<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

JAVA 复制代码
@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.com/mybatis/spr... 分支选择 1.3x,保证所选版本一致。

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

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

主要作用:

  • 注入SqlSessionFactory、SqlSessionTemplate 等核心 bean,这是 Mybatis 核心的类。

  • 提供 AutoConfiguredMapperScannerRegistrar 的注入,用于将带有 @Mapper 的接口生成代理类。

MybatisAutoConfiguration代码分析

JAVA 复制代码
    @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 将复杂留个自己,把简单留个别人的原因。

相关推荐
艾伦~耶格尔30 分钟前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man201734 分钟前
基于spring boot的篮球论坛系统
java·spring boot·后端
2401_858120531 小时前
Spring Boot框架下的大学生就业招聘平台
java·开发语言
S hh1 小时前
【Linux】进程地址空间
java·linux·运维·服务器·学习
Java探秘者1 小时前
Maven下载、安装与环境配置详解:从零开始搭建高效Java开发环境
java·开发语言·数据库·spring boot·spring cloud·maven·idea
攸攸太上1 小时前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
2301_786964361 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
2303_812044461 小时前
Bean,看到P188没看了与maven
java·开发语言
苹果醋32 小时前
大模型实战--FastChat一行代码实现部署和各个组件详解
java·运维·spring boot·mysql·nginx
秋夫人2 小时前
idea 同一个项目不同模块如何设置不同的jdk版本
java·开发语言·intellij-idea