抛出疑問
Mybatis-plus的确能讓我們寫少很多重複代碼,非常好用。那麼其中最友善的就是Mapper接口繼承
BaseMapper
就能獲得增删改查的這個功能。那麼這個功能的底層代碼,究竟是怎麼實作的呢?
原生Mybatis配置的原理
畢竟Mybatis-plus是Mybatis的加強,是以Mybatis-plus肯定是基于Mybatis原來的機制來擴充的,沿着這個思路,我們先搞清楚一個問題,就是
原生的mapper.xml檔案最後是怎麼跟對應的Mapper接口産生聯系的
。
既然是配置,那麼在Mybatis裡肯定有對應的配置類,這個類就是
MappedStatement
。最終在
Configuration
類中把
MappedStatement
對象添加進
mappedStatements
集合中進行管理。源碼如下:
public class Configuration {
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
}
假如有個mapper.xml檔案定義如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yehongzhi.mydemo.mapper.UserMapper">
<select id="getUserList" resultType="com.yehongzhi.mydemo.model.User">
select * from user
</select>
</mapper>
我們用debug模式來驗證一下:

由此可以看出,Mybatis底層在解析Mapper.xml檔案最後是轉成一個
MappedStatement
對象進行管理。跟着這個思路,我們能不能根據特定的規律建立
MappedStatement
對象放進
mappedStatements
集合中,那不就能實作Mybatis-plus的
BaseMapper
的功能了嗎!
Mybatis-plus源碼分析
首先找到
MybatisPlusAutoConfiguration
配置類,會建立MybatisSqlSessionFactoryBean。
并設定
MybatisConfiguration
作為配置類。
這個
MybatisConfiguration
是很重要的類,裡面會初始化一個
mybatisMapperRegistry
,後面有用。
public class MybatisConfiguration extends Configuration {
/**
* Mapper 注冊
*/
protected final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);
}
當建立
MybatisSqlSessionFactoryBean
時,會調用
afterPropertiesSet()
方法建立
sqlSessionFactory
@Override
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
"Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = buildSqlSessionFactory();
}
然後
buildSqlSessionFactory()
方法的主要内容是解析mapper的xml檔案。
然後繼續深入,看
bindMapperForNamespace()
方法。
接着用
MapperAnnotationBuilder
類進行解析。
接着在parse()方法裡進行基本的SQL注入:
關鍵就在這個SQL注入器裡。
是以關鍵在于
AbstractMethod
,這裡用了模闆模式。
public abstract class AbstractMethod implements Constants {
protected Configuration configuration;
protected LanguageDriver languageDriver;
protected MapperBuilderAssistant builderAssistant;
/**
* 注入自定義方法
*/
public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
this.configuration = builderAssistant.getConfiguration();
this.builderAssistant = builderAssistant;
this.languageDriver = configuration.getDefaultScriptingLanguageInstance();
/* 注入自定義方法 */
injectMappedStatement(mapperClass, modelClass, tableInfo);
}
/**
* 注入自定義 MappedStatement
*
* @param mapperClass mapper 接口
* @param modelClass mapper 泛型
* @param tableInfo 資料庫表反射資訊
* @return MappedStatement
*/
public abstract MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo);
}
利用模闆模式,子類隻需要重寫
injectMappedStatement()
方法,上面初始化的部分都可以共用。
AbstractMethod
的子類有很多,我們選個有代表性的看一下,就可以推斷其他的用途,比如Insert類。
由此可看出,BaseMapper裡的語句資訊模闆,來自于枚舉
SqlMethod
最終就是轉成
MappedStatement
對象,然後添加注冊,于是乎就有了這些CRUD操作的方法。
總結
總結一下加載BaseMapper的過程:
- 初始化
和MybatisConfiguration
mybatisMapperRegistry
- 解析Mapper類,擷取AbstractMethod集合。
- 周遊AbstractMethod集合,然後調用各自實作的
方法,注入SQL。injectMappedStatement()
- 添加注冊
對象。MappedStatement
非常感謝你的閱讀,希望這篇文章能給到你幫助和啟發。
覺得有用就點個贊吧,你的點贊是我創作的最大動力~
我是一個努力讓大家記住的程式員。我們下期再見!!!
能力有限,如果有什麼錯誤或者不當之處,請大家批評指正,一起學習交流!