從零開始實現一個簡單的 ibatis SQL 熱部署

在 ibatis 配置文件修改後生效這個問題上,小朋友我嘗試了不少不科學和科學的方式,經過單元測試 or 各類插件。java

單元測試這一方式我比較推薦,不需花費額外的不少時間,可靠和簡單。python

至於後者呢,前有JRebel、HotCode,後有HotCode2,各類折騰。你要問我爲何不換成 MyBatis,我也不知道。sql

因此小朋友我決定本身作一個,或者說是嘗試,哈哈。服務器

空想

咱們在調用 ibatis 的時候,它在背後是如何工做的?架構

例如最多見的一個 delete 操做:app

(List<DogeDO>) sqlMapClientTemplate.delete(NAMESPACE + 「delete", dogeQuery)框架

在developworks上找到了這樣一張時序圖 [1]svn

clipboard.png

顯然,在 SqlMapExecutorDelegate 14 號環節,ibatis 從 MappedStatement 中得到 DeleteStatement,這裏的 Statement,能夠粗鄙的視做真實的 SQL語句,即單元測試

delete * from database;

MappedStatement 是如何初始化的?學習

clipboard.png

學習參考文件[2],瞭解到通過一系列的解析以後,經過以下過程

addStatementNodelets {
     statementParser.parseGeneralStatement {
          newMappedStatementConfig {
               delegate.addMappedStatement(mappedStatement)
          }
     }
}

添加到 mappedStatements 時,進行了鍵值的重複判斷

delegate.addMappedStatement(mappedStatement) {
     if (mappedStatements.containsKey(ms.getId())) {
      throw new SqlMapException("There is already a statement named " + ms.getId() + " in this SqlMap.");
    }
}

若是想在 SQL XML 更改以後從新解析並寫入到 mappedStatements,要把這個重複判斷幹掉,須要經過如下的這些空想步驟。

  • 重寫 addMappedStatement

  • 就須要能介入 delegate

  • 就須要能介入 delegate 初始化的地方,即介入 SqlMapClientImpl

  • 就須要能介入 SqlMapClientImpl 初始化的地方,即介入 SqlMapClientFactoryBean

Google和Stackoverflow一通後,發現能夠經過重寫 delegate 等類的方式解決上述問題的,[3]是一個完整的實現,大神啊。

已有的方案

先正向的看看別人作了什麼,能夠用來抄襲

DySqlMapClientFactoryBean

在 SqlMapClientFactoryBean 的基礎上進行了以下擴展:

  • 初始化時將 configLocation、configLocations 保存下來,有何用?

  • 重寫了 buildSqlMapClient 方法,返回重寫後的 DySqlMapClient

DySqlMapClient

對 SqlMapClientImpl 進行了以下擴展:

  • 將超類初始化爲 重寫後的 DySqlMapExecutorDelegate

  • 自行解析 configLocation || configLocations 對應的配置文件,生成 SQL.XML -> SQL_ID 映射關係

DySqlMapExecutorDelegate

對 SqlMapExecutorDelegate 進行了以下擴展:

  • addMappedStatement,ID值重複時 remove 掉

  • 增長了 checkAndRefreshSqlMap 方法,用來檢查和刷新 Map

  • 重寫各操做實現接口,增長 checkAndRefreshSqlMap 調用

DySqlMapParser

對 SqlMapParser 進行了以下擴展:

  • 增長 resetSqlNodeLets,對 XmlParserState 進行重置。可能會引發 State 混亂

SqlMapConfigUtils

  • readSqlMapFileMapping,解析包含的 SQL XML 文件列表

  • readSqlMap,解析每一個 SQL XML 中的 SQL ID

改進的方案

對[3]進行了測試,發現了一個比較重大的不一樣。咱們的工程將 SQL XML 打包成了 jar,而且,即使是現成的文件 ,流程也變成了修改部署 war 包中的 XML 文件,而不是修改源文件,而後直接生效。因此如今面臨了兩個問題。

  • 如何解決 jar 帶來的文件操做

  • SqlMapFile 直接與源文件關聯

編不下去了

週末撩妹時思考了一下以前遇到的兩個問題

clipboard.png

晚間溜達的時候想到的一出,回家實現勉強能用。

中心思想是搭個HTTP服務,將源文件doge.xml資源化爲http://localhost/doge.xml,iBatis刷新時經過文件名構造URL,讀取HTTP資源並進行解析。

clipboard.png

改造了一個http server

./http-server /src/main/resources/storage/sqlmap -p 59999 -j true

其實你也能夠用

python -m SimpleHTTPServer 59999

弊端就是每次打開不一樣的工程得本身切到目錄下敲命令啓動服務器

事實上,若是你用 Intellij,默認配置下它會在 63342 端口下啓動一個靜態服務器

路徑在

http://localhost:63342/your-project-home-/very-long-module-path/doge.xml

打完收工

[1] 深刻分析 iBATIS 框架之系統架構與映射原理, http://www.ibm.com/developerworks/cn/java/j-lo-ibatis-principle/

[2] ibatis源碼學習(二)初始化和配置文件解析, http://learnworld.iteye.com/blog/1450057

[3] http://bossbase.googlecode.com/svn/trunk/codecup/src/main/java/com/huawei/boss/ibatis/

相關文章
相關標籤/搜索