龙空技术网

MyBatis xml解析源码

四季更新221789896 141

前言:

眼前看官们对“java分析文件”都比较讲究,咱们都需要剖析一些“java分析文件”的相关知识。那么小编也在网上网罗了一些有关“java分析文件””的相关内容,希望小伙伴们能喜欢,大家快快来了解一下吧!

xml文件解析的本质

mybatis中有两类xml文件需要解析,一类是mybatis配置文件,另一类是mybatis的mapper文件。

解析的本质就是将配置文件中的数据信息,解析存储到java对象当中,然后加载到内存使用。

mybatis配置文件的解析

XMLConfigBuilder.java 是用来解析mybatis配置文件的。

解析配置文件是由 SqlSessionFactoryBuilder创建时,调用build构建SqlSessionFactoryBuilder对象时,调用XMLConfigBuilder实现解析。

XMLConfigBuilder中解析配置文件的主要方法

java中方法解析配置文件

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 {      // issue #117 read properties first      propertiesElement(root.evalNode("properties"));      Properties settings = settingsAsProperties(root.evalNode("settings"));      loadCustomVfs(settings);      loadCustomLogImpl(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);    }  }

mybatis配置文件

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        ";><configuration>    <!-- 1、属性:例如jdbc.properties -->    <properties resource="jdbc.properties"></properties>    <!-- 2、设置:定义全局性设置,例如开启二级缓存 -->    <settings>        <setting name="cacheEnabled" value="true"/>    </settings>    <!-- 3、类型名称:为一些类定义别名 -->    <typeAliases>        <typeAlias type="com.panshenlian.pojo.User" alias="user"></typeAlias>    </typeAliases>    <!-- 4、类型处理器:定义Java类型与数据库中的数据类型之间的转换关系 -->    <typeHandlers></typeHandlers>    <!-- 5、对象工厂 -->    <objectFactory type=""></objectFactory>    <!-- 6、插件:mybatis的插件,支持自定义插件 -->    <plugins>        <plugin interceptor=""></plugin>    </plugins>    <!-- 7、环境:配置mybatis的环境 -->    <environments default="development">        <!-- 环境变量:支持多套环境变量,例如开发环境、生产环境 -->        <environment id="development">            <!-- 事务管理器:默认JDBC -->            <transactionManager type="JDBC" />            <!-- 数据源:使用连接池,并加载mysql驱动连接数据库 -->            <dataSource type="POOLED">                <property name="driver" value="com.mysql.jdbc.Driver" />                <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />                <property name="username" value="root" />                <property name="password" value="123456" />            </dataSource>        </environment>    </environments>    <!-- 8、数据库厂商标识 -->    <databaseIdProvider type=""></databaseIdProvider>    <!-- 9、映射器:指定映射文件或者映射类 -->    <mappers>        <mapper resource="UserMapper.xml" />    </mappers>    </configuration>

注意:Mybatis配置文件的属性位置顺序是 固定 的,不允许 颠倒顺序,否则 Mybatis 解析 XML 文件的时候就会抛出异常。

mybatis Mapper文件的解析

XMLConfigBuilder解析mybatis配置文件,最后一个标签就是 mappers 。

//mybatis配置文件的解析mapperElement(root.evalNode("mappers"));

代码中的标签就是对应于 映射器(mappers) 中的标签。

java中mappers标签

映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 形式的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 --><mappers>  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>  <mapper resource="org/mybatis/builder/PostMapper.xml"/></mappers>
<!-- 使用完全限定资源定位符(URL) --><mappers>  <mapper url=";/>  <mapper url=";/>  <mapper url=";/></mappers>
<!-- 使用映射器接口实现类的完全限定类名 --><mappers>  <mapper class="org.mybatis.builder.AuthorMapper"/>  <mapper class="org.mybatis.builder.BlogMapper"/>  <mapper class="org.mybatis.builder.PostMapper"/></mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 --><mappers>  <package name="org.mybatis.builder"/></mappers>

注意 :

扫描接口或者扫描xml文件。如果是扫描的是接口,那么xml和接口要在同一目录下或者指定xml文件所在目录。如果扫描的是xml文件,就不需要扫描接口。

扫描接口为啥需要再次扫描xml文件:使用mapper接口,无法得知xml文件在哪。

扫描xml文件为啥不需要扫描接口:xml文件中的 namespace就是mapper接口 全限定名。

XMLMapperBuilder 解析mapper xml文件的核心

解析mapper 代码

public void parse() {    // 判断资源是否重复加载    //进入判断 是 首次加载    if (!configuration.isResourceLoaded(resource)) {           //解析 mapper xml 文件      configurationElement(parser.evalNode("/mapper"));      //添加资源到配置对象中 用于检测是否 首次加载      configuration.addLoadedResource(resource);      bindMapperForNamespace();    }    parsePendingResultMaps();    parsePendingCacheRefs();    parsePendingStatements();  }

解析mapper 文件内容的代码

private void configurationElement(XNode context) {    try {      String namespace = context.getStringAttribute("namespace");      if (namespace == null || namespace.isEmpty()) {        throw new BuilderException("Mapper's namespace cannot be empty");      }      builderAssistant.setCurrentNamespace(namespace);      cacheRefElement(context.evalNode("cache-ref"));      cacheElement(context.evalNode("cache"));      parameterMapElement(context.evalNodes("/mapper/parameterMap"));      // java 对象属性 与 数据库字段 对照关系      resultMapElements(context.evalNodes("/mapper/resultMap"));      sqlElement(context.evalNodes("/mapper/sql"));      // xml 文件编写的SQL语句      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));    } catch (Exception e) {      throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);    }  }

小结:

SqlSessionFactoryBuilder创建时,创建了XMLConfigBuilder对象,同时XMLConfigBuilder又创建了XMLMapperBuilder对象。调用两个builder对象完成mybatis中xml的解析,至于细节处调用的对象就不复述了。

问题来了,创建的对象最后去哪里了那?

创建SqlSessionFactoryBuilder 使用 build()方法,返回的是SqlSessionFactory对象,但是生成SqlSessionFactory对象时需要,一个入参Configuration对象。

根据上面的代码往下跟踪,得到 XMLConfigBuilder 对象 最后 使用 super(new Configuration()) 生成的Configuration对象。

parseConfiguration方法中,所有解析后的xml数据都是存放在Configuration对象当中。

小结:

Configuration对象存储了,所有的xml解析后的数据。

标签: #java分析文件