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

MyBatis 初始化過程就是生成一些必須的對象放到 Spring 容器中。問題是這個過程到底生成了哪些對象?當遇到 MyBatis 初始化失敗時,如何正確的找到分析問題的切入點?本文將針對這些問題進行介紹。html

本文基於 MyBatis 3Spring,假設讀者已經知道如何使用 Maven 和 MyBatis,以及瞭解 Spring 的容器機制。java

1、Mybatis 三件套

咱們知道 MyBatis 的主要功能是由 SqlSessionFactory 和 Mapper 二者提供的,初始化 MyBatis 就是初始化這兩類對象。除此以外 DataSource 做爲數據庫訪問對象也是必不可少。所以首先咱們應該記住 MyBatis 初始化的核心三件套:git

  • DataSource:它是訪問數據庫所必須的數據源對象,這個初始化失敗就沒法直接訪問數據庫。
  • SqlSessionFactoryBean:這是在 Spring 容器中對 SqlSessionFactory 初始化過程的封裝。
  • MapperScannerConfigurer:這是在 Spring 容器中對 Mapper 初始化過程的封裝。

具體來講,一個簡單的初始化過程就是下面這樣:github

@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 ...;
    }
}

接下來介紹三件套各自如何初始化,下面的內容是能夠實際操做的,不妨動手試試。spring

1. DataSource 初始化

首先咱們建立一個空的 Maven 項目,在 pom.xml 中加入下面的依賴關係:sql

<!-- 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 類,代碼在前面給過了。apache

對應的 DataSource 初始化實現以下:mybatis

@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 對象。app

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 也提供了更多的封裝。有了本文上面的鋪墊,相信讀者對這些封裝方式理解起來也會輕鬆不少。

2、@MapperScan 註解

@MapperScan 註解只不過是 MapperScannerConfigurer 的啓動器而已,使用這個註解,能夠代替前面的 MapperScannerConfigurer 初始化。

3、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 對象。

相關文章
相關標籤/搜索