ibatis源码学习(二)初始化和配置文件解析
在ibatis整体设计和核心流程一文中,我们提到了ibatis框架的初始化过程,本文将深入分析ibatis框架的初始化和配置文件解析过程。本文使用的ibatis版本为2.3.4,不同版本间会略有差异。
问题
在详细介绍ibatis初始化过程之前,让我们先来思考几个问题。
1. ibatis初始化的目标是什么?
上文中提到过,ibatis初始化的核心目标是构造SqlMapClientImpl对象,主要是其内部重要属性delegate这个代理对象的初始化。delegate这个对象耦合了用户端的操作行为和执行环境,持有执行操作的所需要的所有数据。
2. 如何解析ibatis的sqlmap配置文件和sqlmap映射文件?
可以采用通用的xml文件解析工具,如SAX等。
3. 如何将配置文件中每个属性值注入到SqlMapClientImpl对象中?
可以给不同类型节点设置对应的handler,遍历节点时,调用handler对象的处理方法,将节点值注入到SqlMapClientImpl对象的属性中。
带着上面的这些问题,我们开始探索ibatis的初始化过程。
核心类图
初始化过程主要涉及以下几个重要类,理解这些类的含义非常重要。主要类图如下:
1. Nodelet
该接口是对配置文件中节点处理方式的抽象,该接口仅有一个process()方法,表示对该类节点的处理方式。
2. NodeletParser
同SAX类似的一个xml解析器。不同点在于SAX对所有节点采用同样的处理方式,而NodeletParser可以针对不同的节点个性化配置相应的处理方式。 NodeletParser内部维护了一个letMap,这个map维护着节点标识信息XPath和对应的处理方式Nodelet的关系。
3. XmlParserState
用于维护配置文件解析过程中的上下文信息,配置文件解析过程中产生的数据都放入XmlParserState中统一维护。
注意: ibatis2.3.0版本中没有这个类,它使用BaseParser中内部类Variables维护上下文信息。
4. SqlMapConfigParser
用于解析sqlMap配置文件,其内部组合了NodeletParser对象,用于完成sqlMap配置文件解析。该对象构造函数中,完成向NodeletParser属性中添加sqlMap配置文件中节点XPath和对应的Nodelet映射关系。比如<typeAlias>节点的处理方式如下:
6. SqlStatementParser
用于生成sql对应的MappedStatement对象。其内部仅包含一个public方法parseGeneralStatement(Node node, GeneralStatement statement),用于生成MappedStatement对象。
下面以代码中常见的ibatis配置为例,说明ibatis框架的配置文件解析和初始化过程。
常见ibatis配置
初始化过程
1) SqlMapClientFactoryBean初始化
SqlMapClientFactoryBean的初始化方法afterPropertiesSet(),用于构建sqlMapClient对象:
该方法中采用递归方式处理节点的Element、Attribute和Children信息,首先构建当前节点的XPath信息,再调用processNodelet(node, path)处理该节点。
4) 调用SqlMapParser解析sqlMap映射配置文件CaseSQL.xml。
当处理sqlMap配置文件sqlmap-ibatis.xml中的sqlMap节点时,会调用下面的Nodelet进行处理:public void parse(InputStream inputStream) throws NodeletException { parser.parse(inputStream);//调用NodeletParser解析配置文件 }
这里和上面的SqlMapConfigParser解析方式类似,都是调用NodeletParser解析配置文件,不同点在于这两个类是针对不同的配置文件解析(SqlMapConfigParser针对sqlMap配置文件,SqlMapParser针对sqlMap映射文件),所以在各自构造函数插入letMap时,使用的key是自己配置文件里节点的XPath。
5) 调用SqlStatementParser生成MappedStatement。
当解析sqlMap映射文件的select节点时,将调用SqlStatementParser生成MappedStatement。
protected void addStatementNodelets() {
...
parser.addNodelet("/sqlMap/select", new Nodelet() {
public void process(Node node) throws Exception {
statementParser.parseGeneralStatement(node, new SelectStatement());
}
});
}
SqlStatementParser.parseGeneralStatement()的实现这里就不详述了,主要目的是构建MappedStatement,并将配置文件解析后的信息注入到XmlParserState中。
小结
ibatis初始化的核心目标是构建SqlMapClientImpl对象,核心思想如下:
1. 提供NodeletParser配置文件解析类,它维护了节点XPath和对应处理方式的映射关系。
2. SqlMapConfigParser和SqlMapParser在构造方法中向NodeletParser中添加节点XPath和对应处理方式的映射关系。
3. 配置文件解析采用递归方式进行,首先生成当前节点的XPath信息,从NodeletParser获取对应的处理方式并执行。
4. 整个解析过程中每个节点生成的数据统一注入到XmlParserState,最终通过XmlParserStat获取SqlMapClientImpl对象并返回。 1 楼 qq123zhz 2012-03-20 mybatis 解析直接采用了xpath,没有再使用sax了