Configuration of mybatis source code analysis

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>

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324539960&siteId=291194637