赞
踩
欢迎来到MyBatis源码系列的第二篇文章。在上一篇文章中,我们介绍了MyBatis的总览和环境准备。本篇文章将深入探讨MyBatis的配置文件解析过程。配置文件是MyBatis框架的核心组成部分,了解其解析过程对我们理解整个框架的工作原理至关重要。
MyBatis的配置文件是一个XML文件,用于配置和描述MyBatis框架的行为。它定义了数据库连接信息、SQL映射关系、缓存配置、插件配置等。通过解析配置文件,MyBatis可以根据我们的需求进行相应的初始化和配置。
让我们先来看一下MyBatis配置文件的基本结构:
<?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> <!-- 全局属性配置 --> <properties> <!-- 属性配置项 --> </properties> <!-- 数据库连接配置 --> <environments default="development"> <environment id="development"> <!-- 数据库连接信息 --> <transactionManager type="JDBC"> <!-- 事务管理器配置 --> </transactionManager> <dataSource type="POOLED"> <!-- 数据源配置 --> </dataSource> </environment> </environments> <!-- SQL映射配置 --> <mappers> <!-- SQL映射文件引入 --> </mappers> </configuration>
配置文件的根元素是configuration,它包含了三个重要的子元素:properties、environments和mappers。
properties元素用于定义全局属性,这些属性可以在整个配置文件中引用。例如,我们可以定义数据库的连接URL、用户名和密码等属性,并在其他地方引用它们。environments元素用于配置数据库连接信息和事务管理器。我们可以定义多个不同的环境,例如开发环境、测试环境和生产环境,并在需要时切换使用。mappers元素用于引入SQL映射文件,以及其他的Mapper接口配置。SQL映射文件定义了SQL语句和Java方法之间的映射关系,而Mapper接口提供了一种更加便捷的方式来使用这些映射。MyBatis的配置文件加载和解析过程由XMLConfigBuilder类完成。该类是MyBatis源码中的org.apache.ibatis.builder.xml.XMLConfigBuilder,它负责加载和解析配置文件,并构建相应的Configuration对象。
下面是关键代码段的详细解析:
public class XMLConfigBuilder { // ... public Configuration parse() { // 检查配置文件是否已经被解析过,避免重复解析 if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once."); } parsed = true; // 解析配置文件的根节点 parseConfiguration(parser.evalNode("/configuration")); return configuration; } private void parseConfiguration(XNode root) { try { // 解析properties元素 propertiesElement(root.evalNode("properties")); // 解析environments元素 environmentsElement(root.evalNode("environments")); // 解析mappers元素 mappersElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } } private void propertiesElement(XNode context) { if (context != null) { Properties defaults = context.getChildrenAsProperties(); // 设置全局属性 configuration.setVariables(defaults); } } private void environmentsElement(XNode context) { if (context != null) { if (environment == null) { environment = context.getStringAttribute("default"); } for (XNode child : context.getChildren()) { String id = child.getStringAttribute("id"); if (isSpecifiedEnvironment(id)) { TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager")); DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); Environment.Builder environmentBuilder = new Environment.Builder(id) .transactionFactory(txFactory) .dataSource(dsFactory.getDataSource()); configuration.setEnvironment(environmentBuilder.build()); } } } } private void mappersElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); // 扫描指定包下的Mapper接口并注册到Configuration对象中 configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); if (resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); // 解析SQL映射文件 try (InputStream inputStream = Resources.getResourceAsStream(resource)) { XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } } else if (resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); // 解析SQL映射文件 try (InputStream inputStream = Resources.getUrlAsStream(url)) { XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } } else if (resource == null && url == null && mapperClass != null) { // 注册Mapper接口到Configuration对象中 configuration.addMapper(Resources.classForName(mapperClass)); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } } // ... }
以上源码代码段详细解析了配置文件的加载和解析过程。
通过调用parse()方法,开始加载和解析配置文件。首先,解析配置文件的根节点configuration,然后依次解析properties、environments和mappers元素。在解析过程中,根据配置信息创建相应的对象,并将其设置到Configuration对象中。
在propertiesElement()方法中,解析properties元素,并将属性设置到Configuration对象中。在environmentsElement()方法中,解析environments元素,并根据配置信息创建Environment对象,并将其设置到Configuration对象中。在mappersElement()方法中,解析mappers元素,根据指定的SQL映射文件路径或Mapper接口的包名,解析对应的SQL映射文件,并将其添加到Configuration对象中。
通过这一系列的解析过程,MyBatis将配置文件转化为一个全局的Configuration对象,其中包含了MyBatis的全部配置信息。
在本文中,我们深入探讨了MyBatis的配置文件解析过程,并给出了相应的源码代码段,带有详细的中文注释,以便更好地理解。我们了解到配置文件在MyBatis框架中的重要作用,以及其基本的结构。通过解析过程的源码分析,我们可以更清楚地了解MyBatis是如何加载和解析配置文件的,并构建相应的对象。
配置文件的解析过程是理解MyBatis框架的关键之一,它为我们提供了一个全局的配置对象,包含了各项框架的配置信息。在后续的文章中,我们将进一步深入研究MyBatis的其他核心组件和功能。
希望本文对您理解MyBatis的配置文件解析过程有所帮助。如果您有任何问题或者建议,欢迎在评论区留言。在下一篇文章中,我们将继续探索MyBatis源码,从SQL映射文件解析开始。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。