在 MyBatis 框架中,XMLConfigBuilder
是一个关键类,负责解析 mybatis-config.xml
配置文件。理解这个类的工作原理有助于掌握 MyBatis 的配置管理和框架初始化过程。本篇文章将通过自定义实现一个简化版的 XML 配置解析器,并深入解析 MyBatis 中 XMLConfigBuilder
的实现细节。
我们将实现一个简化版的 XML 配置解析器,主要功能是解析
和
节点,并生成一个基本的配置对象。这个实现将帮助我们理解 MyBatis 的配置解析过程,为后续的源码解读打下基础。
在开始实现之前,我们先来看一个典型的 mybatis-config.xml
文件的片段:
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="password"/>
properties>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
settings>
configuration>
节点:加载外部的属性文件或定义属性。
节点:定义 MyBatis 的全局设置,如缓存启用和懒加载等。首先,我们创建一个名为 SimpleXMLConfigParser
的类,用于处理 XML 文件的解析。类中定义了两个 Map
,分别用于存储
和
节点的内容。
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class SimpleXMLConfigParser {
private Map<String, String> properties = new HashMap<>(); // 存储 节点内容
private Map<String, String> settings = new HashMap<>(); // 存储 节点内容
我们编写 parse
方法,该方法负责加载 XML 文件并依次解析
和
节点。
public void parse(String filePath) throws Exception {
// 创建解析器工厂和解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(filePath)); // 解析 XML 文件
// 解析 节点
parseProperties(document);
// 解析 节点
parseSettings(document);
// 校验配置的有效性
validateConfiguration();
}
DocumentBuilderFactory
和 DocumentBuilder
:用于创建 XML 文档解析器。Document
:表示整个 XML 文件内容的对象,供我们解析和操作。
节点接下来,我们编写 parseProperties
方法来解析
节点,并将解析结果存储在 properties
Map 中。
private void parseProperties(Document document) {
NodeList propertyNodes = document.getElementsByTagName("property");
for (int i = 0; i < propertyNodes.getLength(); i++) {
Element property = (Element) propertyNodes.item(i);
properties.put(property.getAttribute("name"), property.getAttribute("value"));
}
}
NodeList
和 Element
:NodeList
是一个包含多个 XML 节点的列表,Element
是具体的 XML 元素节点。我们通过 getAttribute
方法获取属性值。
节点我们以类似的方式解析
节点。
private void parseSettings(Document document) {
NodeList settingNodes = document.getElementsByTagName("setting");
for (int i = 0; i < settingNodes.getLength(); i++) {
Element setting = (Element) settingNodes.item(i);
settings.put(setting.getAttribute("name"), setting.getAttribute("value"));
}
}
节点列表,并将 name
和 value
属性值存储在 settings
Map 中。解析完
和
节点后,我们需要对配置进行校验,确保必须的设置项都已定义。
private void validateConfiguration() {
if (!settings.containsKey("cacheEnabled")) {
throw new IllegalArgumentException("缺少必要的设置:cacheEnabled");
}
}
settings
Map 中是否包含 cacheEnabled
设置项,如果缺少则抛出异常。我们提供 getProperties
和 getSettings
方法,让用户能够获取解析后的配置内容。
public Map<String, String> getProperties() {
return properties;
}
public Map<String, String> getSettings() {
return settings;
}
最后,我们编写一个简单的 main
方法来测试这个解析器。
public static void main(String[] args) throws Exception {
SimpleXMLConfigParser parser = new SimpleXMLConfigParser();
parser.parse("path/to/mybatis-config.xml");
System.out.println("Properties: " + parser.getProperties());
System.out.println("Settings: " + parser.getSettings());
}
}
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class SimpleXMLConfigParser {
private Map<String, String> properties = new HashMap<>();
private Map<String, String> settings = new HashMap<>();
public void parse(String filePath) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(filePath));
parseProperties(document);
parseSettings(document);
validateConfiguration();
}
private void parseProperties(Document document) {
NodeList propertyNodes = document.getElementsByTagName("property");
for (int i = 0; i < propertyNodes.getLength(); i++) {
Element property = (Element) propertyNodes.item(i);
properties.put(property.getAttribute("name"), property.getAttribute("value"));
}
}
private void parseSettings(Document document) {
NodeList settingNodes = document.getElementsByTagName("setting");
for (int i = 0; i < settingNodes.getLength(); i++) {
Element setting = (Element) settingNodes.item(i);
settings.put(setting.getAttribute("name"), setting.getAttribute("value"));
}
}
private void validateConfiguration() {
if (!settings.containsKey("cacheEnabled")) {
throw new IllegalArgumentException("缺少必要的设置:cacheEnabled");
}
}
public Map<String, String> getProperties() {
return properties;
}
public Map<String, String> getSettings() {
return settings;
}
public static void main(String[] args) throws Exception {
SimpleXMLConfigParser parser = new SimpleXMLConfigParser();
parser.parse("path/to/mybatis-config.xml");
System.out.println("Properties: " + parser.getProperties());
System.out.println("Settings: " + parser.getSettings());
}
}
下面是完整的一篇关于 MyBatis 源码解析:XMLConfigBuilder 解析过程 的文章。包括了自定义实现、类图、流程图、源码解析、以及总结的内容。
在 MyBatis 框架中,XMLConfigBuilder
是一个关键类,负责解析 mybatis-config.xml
配置文件。理解这个类的工作原理有助于掌握 MyBatis 的配置管理和框架初始化过程。本篇文章将通过自定义实现一个简化版的 XML 配置解析器,并深入解析 MyBatis 中 XMLConfigBuilder
的实现细节。
我们将实现一个简化版的 XML 配置解析器,主要功能是解析
和
节点,并生成一个基本的配置对象。这个实现将帮助我们理解 MyBatis 的配置解析过程,为后续的源码解读打下基础。
在开始实现之前,我们先来看一个典型的 mybatis-config.xml
文件的片段:
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="password"/>
properties>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="false"/>
settings>
configuration>
节点:加载外部的属性文件或定义属性。
节点:定义 MyBatis 的全局设置,如缓存启用和懒加载等。首先,我们创建一个名为 SimpleXMLConfigParser
的类,用于处理 XML 文件的解析。类中定义了两个 Map
,分别用于存储
和
节点的内容。
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class SimpleXMLConfigParser {
private Map<String, String> properties = new HashMap<>(); // 存储 节点内容
private Map<String, String> settings = new HashMap<>(); // 存储 节点内容
我们编写 parse
方法,该方法负责加载 XML 文件并依次解析
和
节点。
public void parse(String filePath) throws Exception {
// 创建解析器工厂和解析器
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(filePath)); // 解析 XML 文件
// 解析 节点
parseProperties(document);
// 解析 节点
parseSettings(document);
// 校验配置的有效性
validateConfiguration();
}
DocumentBuilderFactory
和 DocumentBuilder
:用于创建 XML 文档解析器。Document
:表示整个 XML 文件内容的对象,供我们解析和操作。
节点接下来,我们编写 parseProperties
方法来解析
节点,并将解析结果存储在 properties
Map 中。
private void parseProperties(Document document) {
NodeList propertyNodes = document.getElementsByTagName("property");
for (int i = 0; i < propertyNodes.getLength(); i++) {
Element property = (Element) propertyNodes.item(i);
properties.put(property.getAttribute("name"), property.getAttribute("value"));
}
}
NodeList
和 Element
:NodeList
是一个包含多个 XML 节点的列表,Element
是具体的 XML 元素节点。我们通过 getAttribute
方法获取属性值。
节点我们以类似的方式解析
节点。
private void parseSettings(Document document) {
NodeList settingNodes = document.getElementsByTagName("setting");
for (int i = 0; i < settingNodes.getLength(); i++) {
Element setting = (Element) settingNodes.item(i);
settings.put(setting.getAttribute("name"), setting.getAttribute("value"));
}
}
节点列表,并将 name
和 value
属性值存储在 settings
Map 中。解析完
和
节点后,我们需要对配置进行校验,确保必须的设置项都已定义。
private void validateConfiguration() {
if (!settings.containsKey("cacheEnabled")) {
throw new IllegalArgumentException("缺少必要的设置:cacheEnabled");
}
}
settings
Map 中是否包含 cacheEnabled
设置项,如果缺少则抛出异常。我们提供 getProperties
和 getSettings
方法,让用户能够获取解析后的配置内容。
public Map<String, String> getProperties() {
return properties;
}
public Map<String, String> getSettings() {
return settings;
}
最后,我们编写一个简单的 main
方法来测试这个解析器。
public static void main(String[] args) throws Exception {
SimpleXMLConfigParser parser = new SimpleXMLConfigParser();
parser.parse("path/to/mybatis-config.xml");
System.out.println("Properties: " + parser.getProperties());
System.out.println("Settings: " + parser.getSettings());
}
}
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class SimpleXMLConfigParser {
private Map<String, String> properties = new HashMap<>();
private Map<String, String> settings = new HashMap<>();
public void parse(String filePath) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(filePath));
parseProperties(document);
parseSettings(document);
validateConfiguration();
}
private void parseProperties(Document document) {
NodeList propertyNodes = document.getElementsByTagName("property");
for (int i = 0; i < propertyNodes.getLength(); i++) {
Element property = (Element) propertyNodes.item(i);
properties.put(property.getAttribute("name"), property.getAttribute("value"));
}
}
private void parseSettings(Document document) {
NodeList settingNodes = document.getElementsByTagName("setting");
for (int i = 0; i < settingNodes.getLength(); i++) {
Element setting = (Element) settingNodes.item(i);
settings.put(setting.getAttribute("name"), setting.getAttribute("value"));
}
}
private void validateConfiguration() {
if (!settings.containsKey("cacheEnabled")) {
throw new IllegalArgumentException("缺少必要的设置:cacheEnabled");
}
}
public Map<String, String> getProperties() {
return properties;
}
public Map<String, String> getSettings() {
return settings;
}
public static void main(String[] args) throws Exception {
SimpleXMLConfigParser parser = new SimpleXMLConfigParser();
parser.parse("path/to/mybatis-config.xml");
System.out.println("Properties: " + parser.getProperties());
System.out.println("Settings: " + parser.getSettings());
}
}
继续生成完整的内容:
在 MyBatis 中,XMLConfigBuilder
是用于解析配置文件的核心类。初始化过程主要包括创建 XPathParser
来处理 XML 文件,并初始化 Configuration
对象来存储解析后的配置信息。
public XMLConfigBuilder(InputStream inputStream) {
this(new XPathParser(inputStream, true, null, new XMLMapperEntityResolver()), null, null);
}
public XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parser = parser;
this.environment = environment;
}
节点在 XMLConfigBuilder
中,propertiesElement
方法用于解析
节点,并将属性加载到 Properties
对象中。这些属性可以来自外部文件,也可以直接在 XML 中定义。
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource-based property file reference.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
resource
和 url
属性允许从外部文件加载属性配置。Resources.getResourceAsProperties
和 Resources.getUrlAsProperties
方法用于将外部文件的内容加载到 Properties
对象中。defaults
对象将合并所有属性,包括外部加载的属性和配置文件中直接定义的属性。最终,这些属性被设置到 XPathParser
和 Configuration
中,供后续解析使用。
节点settingsElement
方法用于解析
节点,将各项设置转换为 Properties
对象并应用到 Configuration
中。
private void settingsAsProperties(XNode context) throws Exception {
if (context != null) {
Properties props = context.getChildrenAsProperties();
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
// 其他设置...
}
}
setAutoMappingBehavior
:控制 MyBatis 自动映射结果集的行为。setCacheEnabled
:启用或禁用 MyBatis 的一级缓存。setLazyLoadingEnabled
:启用或禁用懒加载功能。在 settingsElement
方法中,Properties
对象中的设置会依次被应用到 Configuration
对象中。每个设置对应着 MyBatis 的一项全局配置。
节点MyBatis 的
节点允许配置多个运行环境(如开发、测试和生产),每个环境都有自己的数据源和事务管理器配置。environmentsElement
方法解析此节点,并根据当前配置的环境来选择相应的数据源和事务管理器。
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
String defaultEnvironment = context.getStringAttribute("default");
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id, defaultEnvironment)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
XMLConfigBuilder
解析 mybatis-config.xml
文件的完整流程如下:
XPathParser
和 Configuration
对象。
节点:加载外部属性文件,并将属性应用到 Configuration
中。
节点:将全局设置应用到 Configuration
中。
节点:根据配置的环境选择合适的数据源和事务管理器。Configuration
对象中包含了所有的 MyBatis 配置信息。通过对比,我们可以看到,自定义实现和 XMLConfigBuilder
在整体流程上非常相似,但 XMLConfigBuilder
更加复杂和全面。自定义实现主要涵盖了基本的 XML 解析过程,而 MyBatis 的 XMLConfigBuilder
则加入了更多的细节处理和配置管理功能,例如外部资源加载、属性合并、以及对各项设置的全面支持。
通过这篇文章,我们详细解析了 MyBatis 中 XMLConfigBuilder
的工作流程,并通过自定义实现加深了对 XML 配置解析的理解。掌握这些知识有助于我们更好地理解 MyBatis 的初始化和配置管理。
如果您觉得这篇文章对您有帮助,请点赞、收藏并关注!此外,欢迎在评论区留言,与我们分享您的见解或提出疑问!