1. 程式人生 > >從零搭建Spring Boot腳手架(4):手寫Mybatis通用Mapper

從零搭建Spring Boot腳手架(4):手寫Mybatis通用Mapper

![](https://img2020.cnblogs.com/other/1739473/202008/1739473-20200807135141584-1566985800.png) ## 1. 前言 今天繼續搭建我們的**kono Spring Boot**腳手架,[上一文](https://felord.cn/my-spring-boot-day3.html)把國內最流行的**ORM**框架**Mybatis**也集成了進去。但是很多時候我們希望有一些開箱即用的通用**Mapper**來簡化我們的開發。我自己嘗試實現了一個,接下來我分享一下思路。昨天晚上才寫的,謹慎用於實際生產開發,但是可以借鑑思路。 > Gitee: https://gitee.com/felord/kono day03 分支 > GitHub: https://github.com/NotFound403/kono day03 分支 ## 2. 思路來源 最近在看一些關於**Spring Data JDBC**的東西,發現它很不錯。其中`CrudRepository`非常神奇,只要**ORM**介面繼承了它就被自動加入**Spring IoC**,同時也具有了一些基礎的資料庫操作介面。我就在想能不能把它跟**Mybatis**結合一下。 其實**Spring Data JDBC**本身是支援**Mybatis**的。但是我嘗試整合它們之後發現,要做的事情很多,而且需要遵守很多規約,比如`MybatisContext`的引數上下文,介面名稱字首都有比較嚴格的約定,學習使用成本比較高,不如單獨使用**Spring Data JDBC**爽。但是我還是想要那種通用的CRUD功能啊,所以就開始嘗試自己簡單搞一個。 ## 3. 一些嘗試 最開始能想到的有幾個思路但是最終都沒有成功。這裡也分享一下,有時候失敗也是非常值得借鑑的。 ### 3.1 Mybatis plugin 使用**Mybatis**的外掛功能開發外掛,但是研究了半天發現不可行,最大的問題就是**Mapper**生命週期的問題。 在專案啟動的時候**Mapper**註冊到配置中,同時對應的**SQL**也會被註冊到`MappedStatement`物件中。當執行**Mapper**的方法時會通過代理來根據名稱空間(**Namespace**)來載入對應的`MappedStatement`來獲取**SQL**並執行。 而外掛的生命週期是在`MappedStatement`已經註冊的前提下才開始,根本銜接不上。 ### 3.2 程式碼生成器 這個完全可行,但是造輪子的成本高了一些,而且成熟的很多,實際生產開發中我們找一個就是了,個人造輪子時間精力成本比較高,也沒有必要。 ### 3.3 模擬MappedStatement註冊 最後還是按照這個方向走,找一個合適的切入點把對應通用**Mapper**的`MappedStatement`註冊進去。接下來會詳細介紹我是如何實現的。 ## 4. Spring 註冊Mapper的機制 在最開始沒有**Spring Boot**的時候,大都是這麼註冊**Mapper**的。 ```xml ``` 通過`MapperFactoryBean`每一個**Mybatis Mapper**被初始化並注入了**Spring IoC**容器。所以這個地方來進行通用**Mapper**的注入是可行的,而且侵入性更小一些。那麼它是如何生效的呢?我在大家熟悉的`@MapperScan`中找到了它的身影。下面摘自其原始碼: ```java /** * Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean. * * @return the class of {@code MapperFactoryBean} */ Class factoryBean() default MapperFactoryBean.class; ``` 也就是說通常`@MapperScan`會將特定包下的所有**Mapper**使用`MapperFactoryBean`批量初始化並注入**Spring IoC**。 ## 5. 實現通用Mapper 明白了**Spring** 註冊**Mapper**的機制之後就可以開始實現通用**Mapper**了。 ### 5.1 通用Mapper介面 這裡借鑑**Spring Data**專案中的**CrudRepository