当前位置:   article > 正文

MyBatis源码系列之二:配置文件解析_mybatis配置文件的作用

mybatis配置文件的作用

MyBatis源码系列之二:配置文件解析

引言

欢迎来到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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

配置文件的根元素是configuration,它包含了三个重要的子元素:propertiesenvironmentsmappers

  • 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.");
                    }
                }
            }
        }
    }

    // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

以上源码代码段详细解析了配置文件的加载和解析过程。

通过调用parse()方法,开始加载和解析配置文件。首先,解析配置文件的根节点configuration,然后依次解析propertiesenvironmentsmappers元素。在解析过程中,根据配置信息创建相应的对象,并将其设置到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映射文件解析开始。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/57277?site
推荐阅读
相关标签
  

闽ICP备14008679号