从零开始实现一个简单的 ibatis SQL 热部署

小朋友

在 ibatis 配置文件修改后生效这个问题上,小朋友我尝试了很多不科学和科学的方式,通过单元测试 or 各种插件。

单元测试这一方式我比较推荐,不需花费额外的很多时间,可靠和简单。

至于后者呢,前有JRebel、HotCode,后有HotCode2,各种折腾。你要问我为什么不换成 MyBatis,我也不知道。

所以小朋友我决定自己做一个,或者说是尝试,哈哈。

空想

我们在调用 ibatis 的时候,它在背后是如何工作的?

例如最常见的一个 delete 操作:

(List<DogeDO>) sqlMapClientTemplate.delete(NAMESPACE + “delete", dogeQuery)

在developworks上找到了这样一张时序图 [1]

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/

阅读 3.9k

小朋友的爪哇岛
记录和分享小朋友学习爪哇的过程与心得
395 声望
11 粉丝
0 条评论
395 声望
11 粉丝
文章目录
宣传栏