您现在的位置是:首页 > 正文

理解 MyBatis 是如何在 Spring 容器中初始化的

2024-02-29 15:46:18阅读 1

MyBatis 初始化过程就是 生成一些必须的对象放到 Spring 容器中 。问题是这个过程到底生成了哪些对象?当遇到 MyBatis 初始化失败时,如何正确的找到分析问题的切入点?本文将针对这些问题进行介绍。

本文基于 MyBatis 3 和 Spring ,假设读者已经知道如何使用 Maven 和 MyBatis,以及了解 Spring 的容器机制。

一、Mybatis 三件套

我们知道 MyBatis 的主要功能是由 SqlSessionFactory 和 Mapper 两者提供的,初始化 MyBatis 就是初始化这两类对象。除此之外 DataSource 作为数据库访问对象也是必不可少。因此首先我们应该记住 MyBatis 初始化的核心三件套:

DataSource
SqlSessionFactoryBean
MapperScannerConfigurer

具体来说,一个简单的初始化过程就是下面这样:

@Configuration
public class SpringMyBatisApplication {
    public static void main(String[] args) {
        new AnnotationConfigApplicationContext(SpringMyBatisApplication.class);
    }
    @Bean
    public DataSource dataSource() {
        return ...;
    }
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
        return ...;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        return ...;
    }
}

接下来介绍三件套各自如何初始化,下面的内容是可以实际操作的,不妨动手试试。

1. DataSource 初始化

首先我们创建一个空的 Maven 项目,在 pom.xml 中加入下面的依赖关系:

<!-- Spring -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>

<!-- 数据库 -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-dbcp2</artifactId>
  <version>2.7.0</version>
</dependency>
<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>1.4.199</version>
</dependency>

本文重在演示 MyBatis 的初始化过程,所以没有复杂的 SQL,数据库用的是嵌入式数据库 h2。

然后我们在 com.hyd.mybatis3test 包下面创建一个 SpringMyBatisApplication 类,代码在前面给过了。

对应的 DataSource 初始化实现如下:

@Bean
public DataSource dataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName("org.h2.Driver");
    dataSource.setUrl("jdbc:h2:mem:test");
    return dataSource;
}

2. SqlSessionFactoryBean 初始化

SqlSessionFactoryBean 是对 SqlSessionFactory 初始化过程的封装,Spring 会 在适当的时候执行这个初始化过程,得到最终的 SqlSessionFactory 对象。

SqlSessionFactoryBean 的创建过程如下(注意方法签名在前面的基础上有变动):

@Bean
public SqlSessionFactoryBean sqlSessionFactory(
        DataSource dataSource,
        ResourcePatternResolver resolver
) throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setMapperLocations(resolver.getResources("classpath*:mappers/*.xml"));
    return bean;
}

其中:

  • 第一个参数 dataSource 就是前面生成的数据源对象;
  • 第二个参数 resolver 是 Spring 自动提供的,用于搜索指定路径下的所有 xml 文件。本文不会包含 xml 文件,所以这个配置是无效的,这行可以不写,不过写了也不影响程序运行。

3. MapperScannerConfigurer 初始化

MapperScannerConfigurer 的职责是在指定路径下搜索所有的 Mapper 接口类(参考它的 postProcessBeanDefinitionRegistry() 方法),并通过 MapperFactoryBean 将其注册到 MapperRegistry 中。

@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
    MapperScannerConfigurer configurer = new MapperScannerConfigurer();
    configurer.setBasePackage("com.hyd.mybatis3test");
    return configurer;
}

4. 验证初始化过程成功

为了验证上面的初始化过程完成了,我们在 com.hyd.mybatis3test 包下面创建一个 Mapper 类:

@Mapper
public interface SampleMapper {
    @Update("create table if not exists user(id int)")
    void createUserTable();
}

以及一个 Service 类:

@Service
public static class SampleService {
    @Autowired
    private SampleMapper sampleMapper;
    @PostConstruct
    public void init() {
        sampleMapper.createUserTable();
    }
}

然后别忘了在 SpringMyBatisApplication 顶上添加一个 @ComponentScan(“com.hyd.mybatis3test”) 注解,否则 Spring 会找不到 SampleService。

运行 SpringMyBatisApplication.main() 方法,我们就能在输出中找到这样的内容:

...
SampleMapper.createUserTable - ==>  Preparing: create table if not exists user(id int)
SampleMapper.createUserTable - ==> Parameters:
SampleMapper.createUserTable - <==    Updates: 0
...

这说明这条创建表格的 SQL 语句成功执行了。

在前面三件套的基础上,MyBatis 也提供了更多的封装。有了本文上面的铺垫,相信读者对这些封装方式理解起来也会轻松很多。

二、@MapperScan 注解

@MapperScan 注解只不过是 MapperScannerConfigurer 的启动器而已,使用这个注解,可以代替前面的 MapperScannerConfigurer 初始化。

三、SpringBoot 自动初始化

MyBatis 提供 mybatis-spring-boot-starter 库用于在 Spring Boot 项目中自动初始化:

<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.3</version>
</dependency>

这个所谓的自动初始化实际上就是初始化 SqlSessionFactory 对象。初始化的过程由 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 完成,所需的配置都从 “mybatis-” 前缀的配置属性中获取,具体可以参考 org.mybatis.spring.boot.autoconfigure.MybatisProperties 类。

总结

总之,MyBatis 的初始化核心过程就是三件套的初始化。而在 Spring Boot 应用中,结合自动初始化和 @MapperScan 注解,我们无需手工初始化上这三件套,就能直接从容器中得到 Mapper 对象。

网站文章

  • Python3 实例

    Python3 实例

    一直以来,总想写些什么,但不知从何处落笔。今儿个仓促,也不知道怎么写,就把手里练习过的例子,整理了一下。希望对初学者有用,都是非常基础的例子,很适合初练。好了,Follow me。一、Python Hello World 实例以下实例为学习Python的第一个实例,即如何输出"Hello World!":1 # -*- coding: UTF-8 -*-...

    2024-02-29 15:46:10
  • 深入浅出理解Allan方差分析方法

    深入浅出理解Allan方差分析方法

    深入浅出理解Allan方差分析方法

    2024-02-29 15:46:01
  • python查看包的依赖关系

    问题与背景python在解决兼容性问题的时候,往往需要了解一个包的注意事项,比如版本号的要求,一个包的依赖包有哪些,一个包的具体情况等。参考资料https://www.cnblogs.com/long...

    2024-02-29 15:45:33
  • Audio笔记之SoftAAC2

    SoftAAC2::SoftAAC2( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) : SimpleSoftOMXComponent(name, callbacks, a

    2024-02-29 15:45:25
  • Playwright自动化测试工具之快速实战

    1.前言 只要说到自动化,测试和开发的朋友们都知道selenium。一个自动化测试的神器工具,写个Python自动化脚本解放双手基本上是常规的操作了。虽然selenium有完备的文档,但也需要一定的学...

    2024-02-29 15:45:18
  • oracle 发送邮件

    CREATE OR REPLACE PACKAGE "SAD_SEND_MAIL_PKG" AUTHID CURRENT_USER AS  /* $Header: CUXMAILS.pls 115.14.1159.2 2003/07/24 01:22:18 skkoppul ship $ */  -- Author  : GW10451  -- Created : 2009-03-03

    2024-02-29 15:44:49
  • 高性能fakfa之概述

    高性能fakfa之概述

    Kafka系统架构Kafka介绍Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性:通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以海量的消息存储也能够保持长时间的稳定性能(...

    2024-02-29 15:44:41
  • Python 静态方法和类方法

    静态方法和类方法Python类包含三种方法:实例方法、静态方法和类方法。说明:实例方法只能被实例对象调用,静态方法(由@staticmethod装饰的方法)、类方法(由@classmethod装饰的方...

    2024-02-29 15:44:35
  • 网络篇-网络分层的含义

    网络篇-网络分层的含义

    OSI 七层模型 这是一个理想化的模型,给我们的网络划分了层次。 我们可以将复杂的内容简单化,每一层都专人做专事 [最底层]物理层:只关心如何传输数据,传输的是比特流 数据链路层:主要关心的是将两个设...

    2024-02-29 15:44:05
  • Android动画学习之补间动画和逐帧动画

    一、动画介绍 在Android开发中,动画可划分为两种: 补间动画 主要包括:位置、角度、尺寸、透明度等属性变化。 逐帧动画 通过多张图片轮流播放来显示。 二、补间动画 1. 透明度渐变动画(Alph...

    2024-02-29 15:43:58