Previous SqlSessionFactory of mybatis
http://my.oschina.net/u/657390/blog/653637
The previous article analyzed the creation process of SqlSessionFactory in mybatis. From the previous analysis, it can be seen that a more important part of the creation process is Configuration. This article will focus on analyzing the reading of configuration files.
Let's analyze it with an official example.
mybatis-config.xml is the beginning of mybatis, the configuration of dataSource, mappers, etc. are all here.
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
Entering SqlSessionFactoryBuilder, you can see that all the build methods in the end call the following methods:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
environment: environment, MyBatis can be configured to adapt to a variety of environments, such as development, testing and production.
The relationship between XMLConfigBuilder and Configuration
As you can see from this image, the builder pattern is used.
Code related to reading configuration is involved in the build method
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//构造方法
//XMLMapperEntityResolver离线MyBatis dtd实体解析器
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
The more important part is creating the XPathParser instance
new XPathParser(inputStream, true, props, new XMLMapperEntityResolver())
//创建XPathParser实例
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
The work done by commonConstructor is as follows
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
//使用默认的对象模型得到一个新的XPathFactory实例
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
The relationship between XPathFactory, XPath, XPathFactoryImpl, XPath
It can be seen that the factory method pattern is used.
Next is the process of calling createDocument to create a document
Call parse() after XMLConfigBuilder is created
parser.parse()
//parse()源码
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
Mainly calls parseConfiguration where parser.evalNode("/configuration") gets the root node
/**
* 读取配置文件组装configuration
* @param root 配置文件的configuration节点
*/
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
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 #631
environmentsElement(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);
}
}
From the above code, it can be clearly seen that the most important classes in the process of reading configuration files are: XNode, XPathParser
XNode is an extension of the Node class, and XPathParser is a parser tool class for xml files.
The more important methods in XPathParser are: public XNode evalNode(String expression)
The final call of evalNode is in com.sun.org.apache.xpath.internal.jaxp.XPathImpl
public Object evaluate(String expression, Object item, QName returnType)
XPath related information:
http://www.w3school.com.cn/xpath/index.asp
example
import org.apache.ibatis.io.Resources;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.io.InputStream;
public class XPathExample {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
String resource = "com/analyze/mybatis/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
Document doc = builder.parse(inputStream);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr
= xpath.compile("/configuration/mappers/mapper");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getAttributes().getNamedItem("resource").getNodeValue());
}
}
}
xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>