詳解Mybatis是如何解析配置文件的
緣起
經(jīng)過(guò)前面三章的入門(mén),我們大概了解了Mybatis的主線邏輯是什么樣子的,在本章中,我們將正式進(jìn)入Mybatis的源碼海洋。
Mybatis是如何解析xml的
構(gòu)建Configuration

我們調(diào)用new SqlSessionFactoryBuilder().build()方法的最終目的就是構(gòu)建 Configuration對(duì)象,那么Configuration何許人也?Configuration對(duì)象是一個(gè)配置管家, Configuration對(duì)象之中維護(hù)著所有的配置信息。
Configuration的代碼片段如下
public class Configuration {
//環(huán)境
protected Environment environment;
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled = true;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel = true;
protected boolean cacheEnabled = true;
protected boolean callSettersOnNulls;
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow;
//日志信息的前綴
protected String logPrefix;
//日志接口
protected Class<? extends Log> logImpl;
//文件系統(tǒng)接口
protected Class<? extends VFS> vfsImpl;
//本地Session范圍
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
//數(shù)據(jù)庫(kù)類(lèi)型
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
//延遲加載的方法
protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(
Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
//默認(rèn)執(zhí)行語(yǔ)句超時(shí)
protected Integer defaultStatementTimeout;
//默認(rèn)的執(zhí)行器
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
//數(shù)據(jù)庫(kù)ID
protected String databaseId;
//mapper注冊(cè)表
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
//攔截器鏈
protected final InterceptorChain interceptorChain = new InterceptorChain();
//類(lèi)型處理器
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
//類(lèi)型別名
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
//語(yǔ)言驅(qū)動(dòng)
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
//mapper_id 和 mapper文件的映射
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
"Mapped Statements collection");
//mapper_id和緩存的映射
protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
//mapper_id和返回值的映射
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
//mapper_id和參數(shù)的映射
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
//資源列表
protected final Set<String> loadedResources = new HashSet<String>();
未完.......
}
構(gòu)建MappedStatement
在Configuration中,有個(gè)mappedStatements的屬性,這是個(gè)MappedStatement對(duì)象Map的集合,其key是這個(gè)mapper的namespace+對(duì)應(yīng)節(jié)點(diǎn)的id,而value是一個(gè)MappedStatement對(duì)象。
在構(gòu)建Configuration的時(shí)候,會(huì)去解析我們的配置文件。
解析配置文件的關(guān)鍵代碼如下
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
上訴代碼段倒數(shù)第三行mapperElement(root.evalNode("mappers"));就是解析mappers處就是把我們的mapper文件封裝成MappedStatement對(duì)象,然后保存到Configuration的mappedStatements屬性中,其中key是這個(gè)mapper的namespace+對(duì)應(yīng)節(jié)點(diǎn)的id,而value是一個(gè)MappedStatement對(duì)象。保存的地方關(guān)鍵代碼如下
configuration.addMappedStatement(statement);
addMappedStatement()方法代碼如下
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>(
"Mapped Statements collection");
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
那么這個(gè)MappedStatement的又是何許人也?我們可以簡(jiǎn)單的把MapperStatement理解為對(duì)sql的一個(gè)封裝,在MappedStatement中保存著一個(gè)SqlSource對(duì)象,其中就存有SQL的信息。相關(guān)代碼如下
public final class MappedStatement {
private SqlSource sqlSource;
}
SqlSource 代碼如下
public interface SqlSource {
BoundSql getBoundSql(Object parameterObject);
}
BoundSql代碼如下
public class BoundSql {
private final String sql;
private final List<ParameterMapping> parameterMappings;
}
關(guān)于二級(jí)緩存
我們?cè)贑onfiguration中看到了一個(gè)caches屬性
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
這個(gè)東西的作用是什么呢?其實(shí)是關(guān)于Mybatis的二級(jí)緩存的。在解析配置文件的過(guò)程中,如果用到了二級(jí)緩存,便會(huì)把這個(gè)ID和對(duì)象也保存到configuration的caches中,相關(guān)代碼如下
public void addCache(Cache cache) {
caches.put(cache.getId(), cache);
}
構(gòu)建SqlSessionFactory
在Configuration對(duì)象構(gòu)建完畢之后,就該依賴(lài)Configuration對(duì)象去構(gòu)建SqlSessionFactory對(duì)象了,相關(guān)代碼如下
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
我們暫且把SqlSessionFactory稱(chēng)為SqlSession工廠吧,SqlSessionFactory中有兩個(gè)方法,openSession()和getConfiguration()
SqlSessionFactory代碼如下
public interface SqlSessionFactory {
SqlSession openSession();
//其余openSession重載方法略…
Configuration getConfiguration();
}
構(gòu)建SqlSession
openSession()方法會(huì)返回一個(gè)SqlSession對(duì)象,SqlSession又是何許人也?SqlSession可以理解為程序與數(shù)據(jù)庫(kù)打交道的一個(gè)工具,通過(guò)它,程序可以往數(shù)據(jù)庫(kù)發(fā)送SQL執(zhí)行。
SqlSession代碼如下
public interface SqlSession extends Closeable {
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
//其余增刪查改方法略…
}
總結(jié)
想必你已經(jīng)明白了,Mybatis解析xml最主要的目的其實(shí)是構(gòu)建Configuration對(duì)象,這個(gè)對(duì)象中可以說(shuō)包含著Mybatis的所有配置信息。其中有一個(gè)mappedStatements屬性,這是一個(gè)Map,其中key是這個(gè)mapper的namespace+對(duì)應(yīng)節(jié)點(diǎn)的id,而value是一個(gè)MappedStatement對(duì)象,而MappedStatement中保存著一個(gè)SqlSource對(duì)象,這個(gè)對(duì)象中保存著我們要執(zhí)行的SQL語(yǔ)句。
那么在下一章,我們將一起探究Mybatis是如何執(zhí)行我們的SQL語(yǔ)句的。
到此這篇關(guān)于詳解Mybatis是如何解析配置文件的的文章就介紹到這了,更多相關(guān)Mybatis 解析配置文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis雙重foreach如何實(shí)現(xiàn)遍歷map中的兩個(gè)list數(shù)組
本文介紹了如何解析前端傳遞的JSON字符串并在Java后臺(tái)動(dòng)態(tài)構(gòu)建SQL查詢(xún)條件,首先,通過(guò)JSONArray.fromObject()將JSON字符串轉(zhuǎn)化為JSONArray對(duì)象,遍歷JSONArray,從中提取name和infos,構(gòu)建成Map對(duì)象用于Mybatis SQL映射2024-09-09
org.apache.ibatis.annotations不存在的問(wèn)題
這篇文章主要介紹了org.apache.ibatis.annotations不存在的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
ExecutorService實(shí)現(xiàn)獲取線程返回值
這篇文章主要介紹了ExecutorService實(shí)現(xiàn)獲取線程返回值,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Hibernate映射解析之關(guān)聯(lián)映射詳解
所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫(kù)里,在對(duì)象模型中就是一個(gè)或多個(gè)引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02
Lombok 的@StandardException注解解析
@StandardException 是一個(gè)實(shí)驗(yàn)性的注解,添加到 Project Lombok 的 v__1.18.22 版本中,在本教程中,我們將使用 Lombok 的 @StandardException 注解自動(dòng)生成異常類(lèi)型類(lèi)的構(gòu)造函數(shù),需要的朋友可以參考下2023-05-05
Java中的StampedLock實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中的StampedLock實(shí)現(xiàn)原理詳解,ReentrantReadWriteLock采用悲觀讀,第一個(gè)讀線程拿到鎖后,第二個(gè)/第三個(gè)讀線程可以拿到鎖,特別是在讀線程很多,寫(xiě)線程很少時(shí),需要的朋友可以參考下2024-01-01
Java正則表達(dá)式匹配字符串并提取中間值的方法實(shí)例
正則表達(dá)式常用于字符串處理、表單驗(yàn)證等場(chǎng)合,實(shí)用高效,下面這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式匹配字符串并提取中間值的相關(guān)資料,需要的朋友可以參考下2022-06-06

