Mybatis源码解读(一)解析mybatis配置文件

总览

在这里插入图片描述

上图为mybatis配置文件与实体类的对应关系,先有个总体印象

配置文件解析入口

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  1. 进入build方法,看一下是如何实现的
// Class: SqlSessionFactoryBuilder
public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }

  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.
      }
    }
  }

构建XMLConfigBuilder,这个类负责解析我们的配置文件。

  1. 进入parses方法

    // Class: XMLConfigBuilder
    public Configuration parse() {
      if (parsed) {
        throw new BuilderException("Each XMLConfigBuilder can only be used once.");
      }
      parsed = true;
      // 解析Configuration标签
      parseConfiguration(parser.evalNode("/configuration"));
      return configuration;
    }
    
  2. 进入parseConfiguration,看一下具体实现

// Class: XMLConfigBuilder
private void parseConfiguration(XNode root) {
  try {
    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);
  }
}

这里对Configuration里的字标签进行了挨个解析。

1. 解析properties标签

  1. 先来看一下properties标签的配置内容
<properties resource="db.properties">
    <property name="jdbc.username" value="coolblog"/>
    <property name="hello" value="world"/>
</properties>

可以看到既可以读取资源文件,还可以在子标签中自定义属性。

  1. 看一下源码的解析过程
// Class: XMLConfigBuilder
private void propertiesElement(XNode context) throws Exception {
  if (context != null) {
    // 获取子节点的属性并作为Properties
    Properties defaults = context.getChildrenAsProperties值
    // 获取属性resource的值
    String resource = context.getStringAttribute("resource");
    // 获取属性url的值
    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.  Please specify one or the other.");
    }
    if (resource != null) {
      // resource不为空,将解析到的属性添加到Properties中
      defaults.putAll(Resources.getResourceAsProperties(resource));
    } else if (url != null) {
      // url不为空,将解析到的属性添加到Properties中
      defaults.putAll(Resources.getUrlAsProperties(url));
    }
    // 从configuration中获取属性,也添加到Properties中
    Properties vars = configuration.getVariables();
    if (vars != null) {
      defaults.putAll(vars);
    }
    // 将属性放入到解析器中
    parser.setVariables(defaults);
    // 将属性放入到configuration中
    configuration.setVariables(defaults);
  }
}

2. 解析plugins标签

  1. 先看一下plugin标签的配置内容
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="key" value="value"/>
    </plugin>
</plugins>
  1. 看一下源码的解析过程
// Class: XMLConfigBuilder
private void pluginElement(XNode parent) throws Exception {
  if (parent != null) {
    // 循环处理plugins标签的子标签
    for (XNode child : parent.getChildren()) {
      // 获取interceptor属性的值
      String interceptor = child.getStringAttribute("interceptor");
      // 获取配置信息
      Properties properties = child.getChildrenAsProperties();
      // 实例化拦截器
      Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
      // 设置拦截器的属性
      interceptorInstance.setProperties(properties);
      // 将拦截器添加到configuration中
      configuration.addInterceptor(interceptorInstance);
    }
  }
}

3. 解析environments标签

  1. 先看一下environments标签的配置内容
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>
  1. 看一下源码的解析过程
// Class: XMLConfigBuilder
private void environmentsElement(XNode context) throws Exception {
  if (context != null) {
    if (environment == null) {
      // 获取default属性中的值
      environment = context.getStringAttribute("default");
    }
    for (XNode child : context.getChildren()) {
      String id = child.getStringAttribute("id");
      // 如果default的值与id值相同
      if (isSpecifiedEnvironment(id)) {
        // 通过事务管理气的配置创建TransactionFactory
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
        // 根据配置创建数据源对象
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
        // 将数据源和事务管理器对象添加到Environment中
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);
        // 将Environment添加到configuration中
        configuration.setEnvironment(environmentBuilder.build());
      }
    }
  }
}

            .transactionFactory(txFactory)
            .dataSource(dataSource);
        // 将Environment添加到configuration中
        configuration.setEnvironment(environmentBuilder.build());
      }
    }
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值