Mybatis源碼閱讀(一):Mybatis初始化1.1 解析properties、settings

*************************************優雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程

請關注微信公眾號:HB荷包
在這里插入圖片描述
一個能讓你學習技術和賺錢方法的公眾號,持續更新
*************************************優雅的分割線 **********************************
SimpleExecutor

前言

筆者大概是從今年的5月份開始喜歡上源碼閱讀的,起初是閱讀徐郡明前輩的《Mybatis技術內幕》入的坑,不得不說大佬就是大佬,書中講得東西很細很全。半年過去了,筆者對mybatis略知一二,也開始在為公司搭架構,并且基于Mybatis寫了一套框架,但是盡管如此還是感覺自己對于源碼的理解稍微有點淺。好比是初高中學數學吧,光看例題不做題是記不住的,因此產生了為mybatis寫注釋的想法,想要通過寫注釋的過程,加強對mybatis的理解。雖然現在網上已經有了較全的mybatis中文注釋,但是感覺還是經過自己手敲更能加強記憶,因此便挖下了這個大坑。筆者也希望可以在一年內把這個坑填完,后續關于其他技術的文章可能就比較少,大多數應該就都是mybatis源碼閱讀犀利了

在這里,附上我的碼云地址(別問我為什么是碼云而不是github,下半天代碼下不動急死人)

mybatis中文注釋

同時,我也很歡迎更多的初中級開發者投入到閱讀源碼的行列,并且很樂意大家在我的倉庫上建立自己的分支,希望可以和大家一同進步。

入口

Mybatis

初始化入口文件是SqlSessionFactoryBuilder。該類通過調用XMLConfigBuilder.parse方法初始化配置文件。

public SqlSessionFactory build(Reader reader, String environment, Properties properties) {try {// 讀取配置文件XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);return build(parser.parse());} catch (Exception e) {throw ExceptionFactory.wrapException("Error building SqlSession.", e);} finally {ErrorContext.instance().reset();try {reader.close();} catch (IOException e) {// Intentionally ignore. Prefer previous error.}}}

在XMLConfigBuilder.parse方法中,會先校驗配置文件是否已經解析過了,如果重復解析就拋出異常

public Configuration parse() {if (parsed) {// 已經解析過就不再解析。這里只解析一次throw new BuilderException("每個 XMLConfigBuilder 只能使用一次.");}parsed = true;// 獲取configuration節點進行解析// mybatis解析配置文件使用的是XPathParser,這里的evalNode方法就是解析xml的代碼// 這里對XPathParser不進行注釋,這不屬于mybatis的范疇(其實是懶。)parseConfiguration(parser.evalNode("/configuration"));return configuration;}

parseConfiguration方法中,傳入configuration節點配置,對mybatis-config.xml文件中的該節點進行解析。解析結果會set到Configuration類中。今天只注釋完了properties和settings兩個節點的解析

 /*** 解析mybatis-config.xml文件** @param root*/private void parseConfiguration(XNode root) {try {// 解析properties節點。該節點用來引入外部的資源文件,如db.propertiespropertiesElement(root.evalNode("properties"));// 解析settings節點,校驗配置中的配置項是否合法。該節點用來設置一些mybatis的配置項Properties settings = settingsAsProperties(root.evalNode("settings"));// 加載用戶自己配置的虛擬文件系統loadCustomVfs(settings);// 加載日志loadCustomLogImpl(settings);// TODO 解析typeAliases節點,下次繼續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 #631environmentsElement(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);}}

先看propertiesElement方法,該方法用于解析properties節點。

/*** 解析mybatis-config.xml的properties節點* 將節點中所有的配置set到Configuration中** @param context* @throws Exception*/private void propertiesElement(XNode context) throws Exception {if (context != null) {// 解析拿到節點下的所有子節點配置Properties defaults = context.getChildrenAsProperties();// 獲取properties節點的resource屬性String resource = context.getStringAttribute("resource");// 獲取properties節點的url屬性。String url = context.getStringAttribute("url");if (resource != null && url != null) {// resource和url屬性只能同時存在一個。throw new BuilderException("properties節點不能同時指定resource和url兩個屬性.");}// url和resource屬性只能同時存在一個// 讀取引入的資源文件所有屬性,put到properties節點之下if (resource != null) {defaults.putAll(Resources.getResourceAsProperties(resource));} else if (url != null) {defaults.putAll(Resources.getUrlAsProperties(url));}Properties vars = configuration.getVariables();// 如果configuration之前已經有了配置,也put進去// put這些設置是為了能夠保證后面set回configuration時可以set所有的配置if (vars != null) {defaults.putAll(vars);}parser.setVariables(defaults);// 將Properties節點下所有的配置set到configurationconfiguration.setVariables(defaults);}}

接著就是解析settings節點,該節點用于配置一些mybatis配置項

/*** 解析settings節點** @param context* @return*/private Properties settingsAsProperties(XNode context) {if (context == null) {return new Properties();}// 獲取settings節點下所有的setting節點Properties props = context.getChildrenAsProperties();// 通過Configuration獲取metaClass,用于方便對Configuration進行操作MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);for (Object key : props.keySet()) {// 遍歷setting配置// 如果Configuration沒有這個set方法,說明該配置是無效的if (!metaConfig.hasSetter(String.valueOf(key))) {throw new BuilderException("配置 " + key + " 無效. 請檢查拼寫是否正確.");}}// 校驗完settings之后返回return props;}

解析完settings節點后,程序會加載用戶配置的虛擬文件系統和日志。

/*** 加載用戶自己設置的虛擬文件系統** @param props* @throws ClassNotFoundException*/private void loadCustomVfs(Properties props) throws ClassNotFoundException {// 從settings中拿到name是vfsImpl的配置節點String value = props.getProperty("vfsImpl");if (value != null) {String[] clazzes = value.split(",");for (String clazz : clazzes) {if (!clazz.isEmpty()) {@SuppressWarnings("unchecked")Class<? extends VFS> vfsImpl = (Class<? extends VFS>) Resources.classForName(clazz);// 加載文件系統,set到Configuration中configuration.setVfsImpl(vfsImpl);}}}}/*** 加載日志。代碼比較簡單* 就是從settings中拿到name為logImpl的配置項* 然后set到Configuration中去** @param props*/private void loadCustomLogImpl(Properties props) {Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));configuration.setLogImpl(logImpl);}

引申
上面的代碼中使用到了MetaClass類和Configuration類。下面對這兩個類進行解釋。

首先是Configuration類。該類通過名稱可以很明顯的知道這是mybatis的配置類,對應的是mybatis-config.xml文件的配置。其中今天將properties和settings節點對應的字段進行注釋。

public class Configuration {/*** mybatis-config.xml屬性* settings節點* 允許嵌套語句中使用分頁*/protected boolean safeRowBoundsEnabled;/*** mybatis-config.xml屬性* settings節點* 是否開啟自動駝峰命名規則映射* 即從經典數據庫列名 a_column 到經典 Java 屬性名 aColumn 的類似映射。*/protected boolean mapUnderscoreToCamelCase;/*** mybatis-config.xml文件下* settings節點* 當啟用時,對任意延遲屬性的調用會使帶有延遲加載屬性的對象完整加載;* 反之,每種屬性將會按需加載。*/protected boolean aggressiveLazyLoading;/*** mybatis-config.xml文件下* settings節點* 是否允許單一語句返回多條結果集*/protected boolean multipleResultSetsEnabled = true;/*** mybatis-config.xml文件* settings節點* 允許 JDBC 支持自動生成主鍵*/protected boolean useGeneratedKeys;/*** mybatis-config.xml文件* settings節點* 使用列標簽代替列名*/protected boolean useColumnLabel = true;/*** mybatis-config.xml文件* settings節點* 該配置影響的所有映射器中配置的緩存的全局開關*/protected boolean cacheEnabled = true;/*** mybatis-config.xml文件* settings節點* 指定當結果集中值為null的時候是否調用映射對象的set方法*/protected boolean callSettersOnNulls;/*** mybatis-config.xml文件* settings節點* 指定MyBatis增加到日志名稱的前綴*/protected String logPrefix;/*** mybatis-config.xml文件* settings節點* 指定MyBatis所用日志的具體實現*/protected Class<? extends Log> logImpl;/*** mybatis-config.xml文件* settings節點* VFS含義是虛擬文件系統;* 主要是通過程序能夠方便讀取本地文件系統、FTP文件系統等系統中的文件資源。* Mybatis中提供了VFS這個配置。* 主要是通過該配置可以加載自定義的虛擬文件系統應用程序* 多個文件系統使用逗號隔開*/protected Class<? extends VFS> vfsImpl;/*** mybatis-config.xml文件* settings節點* mybatis利用本地緩存機制防止循環引用的加速重復嵌套查詢。* 默認是SESSION,這種情況會緩存一個會話中執行的所有查詢* 如果是STATEMENT,本地會話僅用在語句執行上* 對相同的SqlSession的不同調用將不會共享數據*/protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;/*** mybatis-config.xml文件* settings節點* 當沒有為菜蔬提供特定的JDBC類型時* 為空值制定JDBC類型*/protected JdbcType jdbcTypeForNull = JdbcType.OTHER;/*** mybatis-config.xml* settings節點* 指定哪個對象的方法觸發一次延遲加載*/protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));/*** mybatis-config.xml文件* settings節點* 設置超時時間*/protected Integer defaultStatementTimeout;/*** mybatis-config.xml文件* settings節點* 為驅動程序設置提示以控制返回結果的獲取大小*/protected Integer defaultFetchSize;/*** mybatis-config.xml文件* settings節點* 配置默認的執行器。* SIMPLE 就是普通的執行器;* REUSE 執行器會重用預處理語句(PreparedStatements);* BATCH 執行器將重用語句并執行批量更新。*/protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;/*** mybatis-config.xml文件* settings節點* 指定 MyBatis 應如何自動映射列到字段或屬性。* NONE 表示取消自動映射;* PARTIAL 只會自動映射沒有定義嵌套結果集映射的結果集。* FULL 會自動映射任意復雜的結果集*/protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;/*** mybatis-config.xml文件下* properties節點的所有配置* 以及該節點對應的resource和url的所有配置* 在XMLConfigBuilder.propertiesElement方法中進行初始化*/protected Properties variables = new Properties();/*** mybatis-config.xml文件* settings節點屬性* 延遲加載的全局開關。* 當開啟時,所有關聯對象都會延遲加載。* 特定關聯關系中可通過設置fetchType屬性來覆蓋該項的開關狀態*/protected boolean lazyLoadingEnabled = false;/*** mybatis-config.xml文件* settings節點* 指定Mybatis創建具有延遲加載能力對象所用到的代理工廠*/protected ProxyFactory proxyFactory = new JavassistProxyFactory();/*** 將數據庫類型轉換成Java類型*/protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);/*** 存儲掃包得到的別名*/protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();}

而MetaClass是反射工具箱里的一個類。Reflector是Mybatis中反射模塊的基礎,每個Reflector對象都對應一個類,在該對象中緩存了反射操作需要使用的元信息,如:可讀屬性、可寫屬性、get、set方法等。ReflectorFactory接口主要實現了對Reflector對象的創建和緩存。而MetaClass則是對Reflector和reflectorFactory的封裝,使其更方便通過反射去操作一個類。

這里就不帖MetaClass的代碼了,感興趣可以自行閱讀。

結語

今天因為時間充裕所以寫的博客比較清晰,后面可能會因為加班所以博客僅僅是對代碼注釋的復制粘貼,還希望讀者可以諒解。這個坑我會繼續填下去的。

最后需要提一下java里的一個容易被忽視的規范,也是面試、大學考試經常喜歡問的內容。

類中定義的成員變量也稱之為“字段”,而屬性則是指get和set方法。屬性只與方法有關而與字段無關。如一個類中存在getName()和setName(String name)方法,不管該類中有沒有name字段,我們都認為它有name這個屬性。反之如果只有字段name而沒有對應的get/set方法,則該類僅僅是有name這個字段而沒有name屬性。后面對于get/set方法我不會稱之為屬性,但是有必要分清楚這兩個概念。
*************************************優雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程

請關注微信公眾號:HB荷包
在這里插入圖片描述
一個能讓你學習技術和賺錢方法的公眾號,持續更新
*************************************優雅的分割線 **********************************
SimpleExecutor

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/536951.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/536951.shtml
英文地址,請注明出處:http://en.pswp.cn/news/536951.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

亞馬遜推薦python_使用python查找amazon類別

我想得到amazon的類別&#xff0c;我計劃廢棄不用API。我已經取消了http://www.amazon.com&#xff0c;我已經在Shop By Department下拉列表中抓取了所有的類別和子類別&#xff0c;我創建了一個web服務來完成這項工作&#xff0c;代碼就在這里route(/hello)def hello():textli…

JavaScript異步基礎

唯一比不知道代碼為什么崩潰更可怕的事情是&#xff0c;不知道為什么一開始它是工作的&#xff01;在 ECMA 規范的最近幾次版本里不斷有新成員加入&#xff0c;尤其在處理異步的問題上&#xff0c;更是不斷推陳出新。然而&#xff0c;我們在享受便利的同時&#xff0c;也應該了…

Flutter、ReactNative、uniapp對比

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

JavaScript數組方法

一、基本類型和引用類型 數值、字符串、布爾值、undefined、null可以直接寫出來&#xff0c;比較簡單的數據稱為基本類型&#xff0c;在比較的時候&#xff0c;是直接按值比較。對象、函數、數組復雜的數據是引用類型&#xff0c;在比較的時候&#xff0c;是按照地址比較。cons…

nodejs mysql模塊_NodeJs使用Mysql模塊實現事務處理

依賴模塊&#xff1a;1. mysql&#xff1a;https://github.com/felixge/node-mysqlnpm install mysql --save2. async&#xff1a;https://github.com/caolan/asyncnpm install async --save(ps: async模塊可換成其它Promise模塊如bluebird、q等)因為Node.js的mysql模塊本身對于…

計數排序vs基數排序vs桶排序

從計數排序說起 計數排序是一種非基于元素比較的排序算法&#xff0c;而是將待排序數組元素轉化為計數數組的索引值&#xff0c;從而間接使待排序數組具有順序性。 計數排序的實現一般有兩種形式&#xff1a;基于輔助數組和基于桶排序。 基于輔助數組 整個過程包含三個數組&…

多線程中ThreadLocal的使用

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

mysql 查看所有表的引擎_MySQL查看數據庫、表的占用空間大小以及某個庫中所有表的引擎類型...

本文章來給大家介紹一些常用的MySQL查看數據庫、表的占用空間大小sql命令吧&#xff0c;希望此教程 對各位同學會有所幫助。查看各庫的大小代碼如下復制代碼SELECT SUM(DATA_LENGTH)SUM(INDEX_LENGTH) FROM information_schema.tables WHERE TABLE_SCHEMAdatabase_name;結果是以…

Fusion組件庫是如何支持多語言能力的

隨著國際化發展&#xff0c;多語言的需求越來越常見&#xff0c;單一的語言已經遠不能滿足需求了。作為一個組件庫&#xff0c;支持多語言也是基本能力。 多語言功能的本質其實是文本的替換&#xff0c;一個詞匯“OK”&#xff0c;在英文語境下是“OK”&#xff0c;日語語境下是…

mysql 存儲過程 replace_mysql replace存儲過程

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云數據庫專家保駕護航&#xff0c;為用戶…

注解版poi操作工具

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

Kali Linux 2019.1 發布,Metasploit 更新到 5.0 版本

百度智能云 云生態狂歡季 熱門云產品1折起>>> Kali Linux 2019.1 發布了&#xff0c;Kali 前身 BackTrack&#xff0c;它是一個基于 Debian 的 Linux 發行版&#xff0c;主要用于信息安全行業&#xff0c;其包含了一系列安全、滲透測試和取證工具。此版本 Linux 內核…

peewee mysql_scrapy中利用peewee插入Mysql

前兩天老大布置一個任務&#xff0c;說爬下來的數據要存入數據庫中&#xff0c;丟給我一個peewee&#xff0c;說用這個。當時的我兩眼一抹黑&#xff0c;這是個什么東西呀&#xff0c;我知道scrapy的數據存入數據庫是在pipelines中進行設置但是peewee是什么東西呢。經過兩天不懈…

Java版數據結構與算法——線性表

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

基于 CODING 的 Spring Boot 持續集成項目

本文作者&#xff1a;CODING 用戶 - 廖石榮 持續集成的概念 持續集成(Continuous integration,簡稱 CI&#xff09;是一種軟件開發實踐&#xff0c;即團隊開發成員經常集成他們的工作&#xff0c;通常每個成員每天至少集成一次&#xff0c;也就意味著每天可能會發生多次集成。每…

lvs mysql 端口_LVS配置及多端口服務配置

一、5、各主機IP地址&#xff1a;主機IP網關Client192.168.86.116RouterF0/0:192.168.x.xFo/1:192.168.xx.xxF0/1DirectorEth0:192.168.86.111/24(DIP)Eth0:1:192.168.86.254/32(VIP)F0/1Real 1Eth0:192.168.86.112/24(DIP)lo:1:192.168.86.254/32(VIP)F0/1Real 2Eth0:192.168.…

Mybatis組成部分

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

Stream流與Lambda表達式(一) 雜談

一、流 轉換為數組、集合 package com.java.design.java8.Stream;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;import java.util.A…

一年java工作經驗-面試總結

*************************************優雅的分割線 ********************************** 分享一波:程序員賺外快-必看的巔峰干貨 如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程 請關注微信公眾號:HB荷包 一個能讓你學習技術和賺錢方法的公眾號,持續更…

linux mysql python包_03_mysql-python模塊, linux環境下python2,python3的

---恢復內容開始---1、Python2 正常[rootIP ~]#pip install mysql-pythonDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 wont be maintained after that date. A future version of pip will drop …