MyBatis如何解析mapper.xml中的sql相关信息(一
在日常的解析XML文件有四中主流的方法,DOM解析,SAX解析,JDOM解析,DOM4j解析,那么在Mybatis中用到了DOM的解析方法,JDOM和DOM4j是开源jar包,其中DOM4j运用的较多,性能较好,我们可以日后研究学习他的解析细节。
在Mybatis的解析中它自己新写了一个类XNode的节点类,了解xml解析的不难理解它意义。
现在开始从源码看起,首先从下面加载代码中找到入口
//config.xml配置文件,没有整合spring,mapper.xml都在配置文件里的mappers标签中
Reader reader = Resources.getResourceAsReader("/config.xml");
SqlSessionFactory sq = new SqlSessionFactoryBuilder().build(reader);
进入到build()方法后,定位到这里的build()方法,finally部分源码删除了,占地方。。
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
SqlSessionFactory var5;
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
var5 = this.build(parser.parse());
} catch (Exception var14) {
throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
}
return var5;
}
方法里的三个参数分别是,配置文件流,其他参数俩都为空,首先是构造了XMLConfigBuilder类的构造方法,到这个构造方法看一下
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
继续跳XPathParser类的构造方法
public XPathParser(Reader reader, boolean validation, Properties variables, EntityResolver entityResolver) {
this.commonConstructor(validation, variables, entityResolver);
this.document = this.createDocument(new InputSource(reader));
}
首先commonConstructor方法简单的操作后,this.createDocument()方法看一下
private Document createDocument(InputSource inputSource) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(this.validation);
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(this.entityResolver);
builder.setErrorHandler(new ErrorHandler() {
//...省略了。
});
return builder.parse(inputSource);
} catch (Exception var4) {
throw new BuilderException("Error creating document instance. Cause: " + var4, var4);
}
}
这里明显看到了try的第一行代码:DocumentBuilderFactory.newInstance();随后又
return builder.parse(inputSource); 说明讲Mybatis配置文件流进行了JDK的DOM解析后返回一个Document对象。
这时候我们再回到SqlSessionFactoryBuilder类的build()方法中再看构造完XMLConfigBuilder类返回Document的下一步: var5 = this.build(parser.parse());
这里看出是解析的方法parse(),具体进到这里面看下XMLConfigBuilder类中的parse()
public Configuration parse() {
if(this.parsed) {
throw new BuilderException("Each MapperConfigParser can only be used once.");
} else {
this.parsed = true;
this.parseConfiguration(this.parser.evalNode("/configuration"));
return this.configuration;
}
}
在这个方法中首先判断了this.parsed真假,其实在这个类的构造方法里已经定义了:
this.parsed = false;所以我们进入到下面的else,这也是防止一个文件只能被解析一次。
看这个方法parser.evalNode(),里面的参数是xml文件的xpath 路径,/configuration,是不是很兴奋,这是配置文件的根节点。进入到方法中,定位到这三个方法
public XNode evalNode(String expression) {
return this.evalNode(this.document, expression);
}
public XNode evalNode(Object root, String expression) {
Node node = (Node)this.evaluate(expression, root, XPathConstants.NODE);
return node == null?null:new XNode(this, node, this.variables);
}
private Object evaluate(String expression, Object root, QName returnType) {
try {
return this.xpath.evaluate(expression, root, returnType);
} catch (Exception var5) {
throw new BuilderException("Error evaluating XPath. Cause: " + var5, var5);
}
}
其实呢很简单就是获得MyBatis配置文件中的configuration节点下的所有内容!依旧返回XNode对象,最后在回到XMLConfigBuilder类中的parse()解析方法中。
目前,从源码清楚地看到通过DOM解析配置文件,最后返回configuration节点下的左右内容的XNode对象后,进行其他的解析。其他部分如何解析,继续下一篇的源码阅读!今儿就到这。