在 Spring Boot 啟動過程中,MyBatis-Plus 的加載和初始化涉及多個階段的工作。這些工作包括 MyBatis-Plus 自身的配置解析、Mapper 接口的掃描與注冊、SQL 語句的動態注入以及底層 MyBatis 的初始化等。以下是對整個過程的詳細分析:
1. Spring Boot 啟動時對 MyBatis-Plus 的加載
Spring Boot 在啟動時會對 MyBatis-Plus 進行自動配置(AutoConfiguration),并通過依賴注入的方式完成組件的初始化。以下是關鍵步驟:
(1)@EnableAutoConfiguration
?和?MybatisPlusAutoConfiguration
- Spring Boot 的核心特性是基于約定優于配置的原則,通過?
@EnableAutoConfiguration
?注解自動加載相關的 Starter 配置。 mybatis-plus-boot-starter
?提供了?MybatisPlusAutoConfiguration
?類,該類負責完成 MyBatis-Plus 的自動配置。
主要功能:
- 數據源配置:加載?
DataSource
,并將其注入到 MyBatis 中。 - SqlSessionFactory 初始化:創建?
SqlSessionFactory
?對象,用于管理 SQL 會話。 - Mapper 掃描:掃描標注了?
@Mapper
?或被?@MapperScan
?指定的包路徑下的所有 Mapper 接口,并將其注冊為 Spring 容器中的 Bean。 - 全局配置:讀取?
application.yml
?或?application.properties
?中的 MyBatis-Plus 配置項(如分頁插件、邏輯刪除配置等)。
(2)MapperScannerConfigurer
?的作用
- MyBatis-Plus 使用?
MapperScannerConfigurer
?來掃描所有的 Mapper 接口。 - 掃描到的每個 Mapper 接口都會被注冊為一個 Spring Bean,并與底層的 MyBatis 映射器綁定。
(3)SqlSessionTemplate
?和?SqlSession
?的初始化
- Spring Boot 會創建?
SqlSessionTemplate
,它是 MyBatis 的核心組件之一,用于執行 SQL 語句。 SqlSessionTemplate
?內部封裝了?SqlSession
,并通過線程安全的方式管理數據庫連接。
2. MyBatis-Plus 的加載和初始化
MyBatis-Plus 在 Spring Boot 啟動時完成了自身的初始化工作,主要包括以下幾個方面:
(1)全局配置加載
MyBatis-Plus 會從配置文件中讀取全局配置項,例如:
- 數據庫字段命名規則(駝峰命名或下劃線命名)。
- 主鍵生成策略。
- 字段自動填充策略。
- 分頁插件、邏輯刪除插件等。
配置項通常通過 application.yml
或 application.properties
提供,例如:
yaml
mybatis-plus:global-config:db-config:table-underline: true # 啟用駝峰命名規則id-type: auto # 主鍵生成策略
(2)Mapper 接口的動態代理
MyBatis-Plus 會為每個 Mapper 接口生成動態代理對象。這些代理對象實現了接口中定義的方法,并通過 MyBatis 的底層機制執行 SQL 操作。
動態代理的核心邏輯:
- 方法攔截:當調用 Mapper 接口中的方法時,動態代理會攔截調用,并根據方法簽名生成對應的 SQL 語句。
- SQL 注入:如果啟用了自定義 SQL 注入器(如?
InsertBatchSomeColumn
),則會在啟動時將這些方法的 SQL 注入到 MyBatis 的?MappedStatement
?中。
(3)SQL 方法的動態注入
MyBatis-Plus 提供了許多內置的通用方法(如 insert
、selectById
等),這些方法對應的 SQL 語句是在啟動時動態生成并注入到 MyBatis 的 MappedStatement
中的。
動態注入的過程:
- 掃描 Mapper 接口:MyBatis-Plus 會掃描所有的 Mapper 接口,并為其注冊默認的 SQL 方法。
- 生成 SQL 語句:對于每個方法,MyBatis-Plus 會根據方法簽名和實體類的元信息(如表名、字段名)動態生成 SQL 語句。
- 注入?
MappedStatement
:生成的 SQL 語句會被注入到 MyBatis 的?MappedStatement
?中,供后續執行使用。
(4)插件的初始化
MyBatis-Plus 提供了許多內置插件(如分頁插件、邏輯刪除插件等),這些插件會在啟動時被初始化并注冊到 MyBatis 的攔截器鏈中。
常見插件:
- 分頁插件(PaginationInterceptor):用于支持分頁查詢。
- 邏輯刪除插件(LogicSqlInjector):用于支持邏輯刪除功能。
- 性能分析插件(PerformanceInterceptor):用于分析 SQL 執行性能。
插件的初始化通常通過配置文件或代碼顯式注冊,例如:
@Bean
public PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();
}
3. 底層 MyBatis 的初始化
MyBatis 是 MyBatis-Plus 的底層框架,因此 MyBatis-Plus 的初始化也依賴于 MyBatis 的核心機制。以下是 MyBatis 的初始化過程:
(1)SqlSessionFactory
?的創建
SqlSessionFactory
?是 MyBatis 的核心組件,用于創建?SqlSession
?對象。- 在 Spring Boot 中,
SqlSessionFactory
?通常通過?SqlSessionFactoryBean
?創建。
初始化流程:
- 加載 MyBatis 配置文件:讀取?
mybatis-config.xml
?或通過 Java 配置類提供的配置項。 - 解析 Mapper XML 文件:如果存在 XML 格式的 Mapper 文件,MyBatis 會解析這些文件并將其中的 SQL 語句注冊到?
MappedStatement
?中。 - 創建?
SqlSessionFactory
?實例:完成上述步驟后,SqlSessionFactory
?被創建并注入到 Spring 容器中。
(2)MapperRegistry
?的初始化
MapperRegistry
?是 MyBatis 的一個內部組件,用于管理所有的 Mapper 接口。- 在啟動時,MyBatis 會將所有的 Mapper 接口注冊到?
MapperRegistry
?中。
(3)Configuration
?的初始化
Configuration
?是 MyBatis 的核心配置對象,包含所有的全局配置項和映射信息。- 在啟動時,MyBatis 會初始化?
Configuration
?對象,并將所有的?MappedStatement
、插件、類型處理器等注冊到其中。
4. 總結:工作原理及底層邏輯
以下是 Spring Boot 啟動時 MyBatis-Plus 的加載和初始化過程的總結:
-
Spring Boot 自動配置:
- 加載?
DataSource
。 - 初始化?
SqlSessionFactory
。 - 掃描并注冊 Mapper 接口。
- 加載?
-
MyBatis-Plus 的初始化:
- 加載全局配置項。
- 動態生成并注入 SQL 方法。
- 初始化插件(如分頁插件、邏輯刪除插件)。
-
MyBatis 的底層初始化:
- 創建?
SqlSessionFactory
。 - 解析 Mapper XML 文件。
- 初始化?
MapperRegistry
?和?Configuration
。
- 創建?
-
運行時行為:
- 當調用 Mapper 接口中的方法時,動態代理會攔截調用,并通過 MyBatis 的底層機制執行 SQL 操作。
MyBatis-Plus 在 Spring Boot 啟動時會完成實體類的基礎 SQL(如 SELECT
、INSERT
、UPDATE
、DELETE
等)的組裝和加載,并將這些 SQL 注冊到 MyBatis 的 Mapper
映射中。這個過程可以理解為 提前初始化好基礎 SQL,以便在運行時直接使用。
以下是詳細的分析和工作原理:
1. 基礎 SQL 的組裝
MyBatis-Plus 通過動態生成的方式,為每個實體類生成一組通用的基礎 SQL(即 CRUD 操作對應的 SQL)。這些 SQL 是基于實體類的注解(如 @TableName
和 @TableField
)以及全局配置(如字段命名規則、主鍵策略等)動態生成的。
(1)SQL 的生成邏輯
MyBatis-Plus 使用 AbstractMethod
類及其子類來定義每種 SQL 方法的生成邏輯。例如:
Insert
?方法:生成插入語句(INSERT INTO table_name (column1, column2) VALUES (?, ?)
)。SelectById
?方法:生成根據主鍵查詢的語句(SELECT * FROM table_name WHERE id = ?
)。Update
?方法:生成更新語句(UPDATE table_name SET column1 = ?, column2 = ? WHERE id = ?
)。Delete
?方法:生成刪除語句(DELETE FROM table_name WHERE id = ?
)。
這些方法的具體實現位于 com.baomidou.mybatisplus.core.injector.methods
包中。
(2)動態生成 SQL
MyBatis-Plus 會根據實體類的元信息(如表名、字段名、主鍵等)動態生成 SQL 語句。例如:
- 如果實體類中有?
@TableName("user")
?注解,則生成的 SQL 中的表名為?user
。 - 如果字段上有?
@TableField("name")
?注解,則生成的 SQL 中的字段名為?name
。 - 如果啟用了駝峰命名規則(
table-underline: true
),則會自動將字段名從駝峰命名轉換為下劃線命名。
2. SQL 的注冊過程
生成的基礎 SQL 會被注冊到 MyBatis 的 MappedStatement
中,這是 MyBatis 的核心組件之一,用于存儲 SQL 語句及其映射信息。
(1)什么是?MappedStatement
?
MappedStatement
是 MyBatis 的一個內部對象,用于描述一條 SQL 語句的執行細節,包括:
- SQL 語句本身。
- 參數類型。
- 返回值類型。
- 執行器類型(如?
SIMPLE
、REUSE
、BATCH
)。
(2)SQL 注冊的流程
在 Spring Boot 啟動時,MyBatis-Plus 會完成以下步驟:
- 掃描 Mapper 接口:通過?
@MapperScan
?或?MapperScannerConfigurer
?掃描所有的 Mapper 接口。 - 生成 SQL:為每個 Mapper 接口中的方法動態生成 SQL 語句。
- 注冊到?
MappedStatement
:將生成的 SQL 注冊到 MyBatis 的?Configuration
?對象中,并與對應的?Mapper
?方法綁定。
示例:
假設有一個實體類 User
和對應的 UserMapper
:
@TableName("user")
public class User {private Long id;private String name;
}public interface UserMapper extends BaseMapper<User> {
}
在啟動時,MyBatis-Plus 會為 UserMapper
注冊以下基礎 SQL:
SELECT * FROM user WHERE id = ?
(selectById
?方法)INSERT INTO user (id, name) VALUES (?, ?)
(insert
?方法)UPDATE user SET name = ? WHERE id = ?
(updateById
?方法)DELETE FROM user WHERE id = ?
(deleteById
?方法)
這些 SQL 會被存儲在 MappedStatement
中,并與 UserMapper
的方法綁定。
3. 提前初始化的好處
MyBatis-Plus 的這種提前初始化機制有以下好處:
(1)性能優化
- 減少運行時開銷:SQL 語句在啟動時就已經生成并注冊,運行時無需再動態生成 SQL,從而提高了執行效率。
- 緩存復用:
MappedStatement
?是 MyBatis 的緩存對象,同一 SQL 語句在多次調用時可以直接復用,避免重復解析。
(2)簡化開發
- 零配置:開發者無需手動編寫 SQL 語句,MyBatis-Plus 會根據實體類自動生成基礎 SQL。
- 統一管理:所有基礎 SQL 都由 MyBatis-Plus 統一生成和管理,減少了代碼冗余和潛在錯誤。
(3)靈活性
- 可擴展性:如果需要自定義 SQL 方法,可以通過實現?
AbstractMethod
?或自定義?SqlInjector
?來擴展功能。 - 插件支持:MyBatis-Plus 的插件機制(如分頁插件、邏輯刪除插件)可以在 SQL 注冊過程中對生成的 SQL 進行增強或修改。
4. 動態代理與運行時行為
雖然基礎 SQL 在啟動時已經生成并注冊,但實際的 SQL 執行是由 MyBatis 的動態代理機制完成的。以下是運行時的行為:
(1)動態代理攔截
當調用 Mapper
接口中的方法時,MyBatis 的動態代理會攔截調用,并根據方法簽名找到對應的 MappedStatement
。
(2)參數綁定
MyBatis 會根據方法的參數類型和 SQL 中的占位符(?
)進行參數綁定。例如:
java
User user = userMapper.selectById(1L);
在運行時,MyBatis 會將 1L
綁定到 SQL 中的 ?
,生成最終的 SQL:
sql
SELECT * FROM user WHERE id = 1;
(3)執行 SQL
綁定參數后,MyBatis 會通過 SqlSession
執行 SQL,并返回結果。
5. 總結
- SQL 的組裝:MyBatis-Plus 在啟動時會根據實體類的元信息動態生成基礎 SQL(如?
SELECT
、INSERT
、UPDATE
、DELETE
?等)。 - SQL 的注冊:生成的 SQL 會被注冊到 MyBatis 的?
MappedStatement
?中,并與?Mapper
?方法綁定。 - 提前初始化的好處:這種方式減少了運行時的開銷,簡化了開發,并提供了良好的靈活性和擴展性。