詳解Mybatis是如何解析配置文件的
緣起
經(jīng)過前面三章的入門,我們大概了解了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ù)庫類型 protected JdbcType jdbcTypeForNull = JdbcType.OTHER; //延遲加載的方法 protected Set<String> lazyLoadTriggerMethods = new HashSet<String>( Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" })); //默認(rèn)執(zhí)行語句超時(shí) protected Integer defaultStatementTimeout; //默認(rèn)的執(zhí)行器 protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE; //數(shù)據(jù)庫ID protected String databaseId; //mapper注冊表 protected final MapperRegistry mapperRegistry = new MapperRegistry(this); //攔截器鏈 protected final InterceptorChain interceptorChain = new InterceptorChain(); //類型處理器 protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(); //類型別名 protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry(); //語言驅(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的又是何許人也?我們可以簡單的把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í)緩存
我們在Configuration中看到了一個(gè)caches屬性
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
這個(gè)東西的作用是什么呢?其實(shí)是關(guān)于Mybatis的二級(jí)緩存的。在解析配置文件的過程中,如果用到了二級(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)建完畢之后,就該依賴Configuration對(duì)象去構(gòu)建SqlSessionFactory對(duì)象了,相關(guān)代碼如下
public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }
我們暫且把SqlSessionFactory稱為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ù)庫打交道的一個(gè)工具,通過它,程序可以往數(shù)據(jù)庫發(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ì)象中可以說包含著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語句。
那么在下一章,我們將一起探究Mybatis是如何執(zhí)行我們的SQL語句的。
到此這篇關(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查詢條件,首先,通過JSONArray.fromObject()將JSON字符串轉(zhuǎn)化為JSONArray對(duì)象,遍歷JSONArray,從中提取name和infos,構(gòu)建成Map對(duì)象用于Mybatis SQL映射2024-09-09org.apache.ibatis.annotations不存在的問題
這篇文章主要介紹了org.apache.ibatis.annotations不存在的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10ExecutorService實(shí)現(xiàn)獲取線程返回值
這篇文章主要介紹了ExecutorService實(shí)現(xiàn)獲取線程返回值,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Hibernate映射解析之關(guān)聯(lián)映射詳解
所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫里,在對(duì)象模型中就是一個(gè)或多個(gè)引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02Lombok 的@StandardException注解解析
@StandardException 是一個(gè)實(shí)驗(yàn)性的注解,添加到 Project Lombok 的 v__1.18.22 版本中,在本教程中,我們將使用 Lombok 的 @StandardException 注解自動(dòng)生成異常類型類的構(gòu)造函數(shù),需要的朋友可以參考下2023-05-05Java中的StampedLock實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中的StampedLock實(shí)現(xiàn)原理詳解,ReentrantReadWriteLock采用悲觀讀,第一個(gè)讀線程拿到鎖后,第二個(gè)/第三個(gè)讀線程可以拿到鎖,特別是在讀線程很多,寫線程很少時(shí),需要的朋友可以參考下2024-01-01Java正則表達(dá)式匹配字符串并提取中間值的方法實(shí)例
正則表達(dá)式常用于字符串處理、表單驗(yàn)證等場合,實(shí)用高效,下面這篇文章主要給大家介紹了關(guān)于Java正則表達(dá)式匹配字符串并提取中間值的相關(guān)資料,需要的朋友可以參考下2022-06-06