【源碼篇】聊聊源碼mybatis(構建加載初始化源碼分析)


在這裏插入圖片描述

該節內容主要將Mybatis初始化內容,回顧下我們第一節的核心重點圖。

在這裏插入圖片描述

舉個case:Mybatis初始化的加載過程時序圖

在這裏插入圖片描述

3.1、XML的配置解析示例

3.1.1、mybatis-config.xml的使用示例

//1、xml的協議頭
<?xml version="1.0" encoding="UTF-8" ?>
//2、mybatis對於xml,Configuration配置文件的約束協議
  <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
//3、全局配置對象
<configuration>
  //3.1.1、數據源配置1:通過屬性注入數據源
  <properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/>
  //3.1.2、數據源配置2:通過直接配置
  //3.2、全局配置對象的屬性
  <settings>
    //是否開啓緩存
    <setting name="cacheEnabled" value="true"/>
    //是否開啓懶加載
    <setting name="lazyLoadingEnabled" value="false"/>
    //是否允許返回多個結果集
    <setting name="multipleResultSetsEnabled" value="true"/>
    //是否使用駝峯標示屬性
    <setting name="useColumnLabel" value="true"/>
    //是否使用生成主鍵策略
    <setting name="useGeneratedKeys" value="false"/>
    //默認的執行器類型
    <setting name="defaultExecutorType" value="SIMPLE"/>
    //默認的會話超時時間單位s
    <setting name="defaultStatementTimeout" value="25"/>
  </settings>
  //3.3、實體對象別名映射
  <typeAliases>
    <typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/>
  </typeAliases>
  //3.3、指定類型處理器
  <typeHandlers>
    <typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
  </typeHandlers>
  //3.4、對象工廠
  <objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory">
    <property name="objectFactoryProperty" value="100"/>
  </objectFactory>
  //3.5、配置會話攔截插件
  <plugins>
    <plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
      <property name="pluginProperty" value="100"/>
    </plugin>
  </plugins>
  //3.6、配置環境變量: MyBatis 系統的核心設置,包括獲取數據庫連接實例的數據源(DataSource)以及決定事務作用域和控制方式的事務管理器(TransactionManager)
  <environments default="development">
    //3.6.1、環境配置變量可以通過ID來區分dev-uat-pre-pro
    <environment id="development">
       //3.6.1.1、事務管理器
      <transactionManager type="JDBC">
        <property name="" value=""/>
      </transactionManager>
      //3.6.1.2、數據源配置
      <dataSource type="UNPOOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  //3.7、mapper接口配置,包含了 SQL 代碼和映射定義信息
  <mappers>
    <mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
  </mappers>

</configuration>

3.1.2、Mapper.xml的使用示例

//1、xml的定義
<?xml version="1.0" encoding="UTF-8" ?>
//2、mapper協議的約束
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
//3、映射類路徑的mapper,實際上是和對應的java類綁定
<mapper namespace="org.apache.ibatis.domain.blog.mappers.AuthorMapper">
//4、mapper接口方法:根據主鍵ID查詢返回結果map的
	<parameterMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
		<parameter property="id" />
	</parameterMap>
//5、mapper接口方法:對於實體對象和數據庫字段的映射情況
	<resultMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
    //字段列和對象屬性的映射
		<id column="id" property="id" />
		<result property="username" column="username" />
		<result property="favouriteSection" column="favourite_section" />
	</resultMap>
//6、mapper接口方法:包含嵌套的對象屬性字段映射情況
	<resultMap id="selectImmutableAuthor" type="org.apache.ibatis.domain.blog.ImmutableAuthor">
    //參數和Java類型映射
		<constructor>
			<idArg column="id" javaType="_int" />
			<arg column="username" javaType="string" />
			<arg column="favourite_section" javaType="org.apache.ibatis.domain.blog.Section" />
		</constructor>
	</resultMap>
//7、mapper接口方法:查詢所有結果
	<select id="selectAllAuthors" resultType="org.apache.ibatis.domain.blog.Author">
		select * from author
	</select>
//8、mapper接口方法:查詢返回set集
	<select id="selectAllAuthorsSet" resultType="org.apache.ibatis.domain.blog.Author">
		select * from author
	</select>
//9、mapper接口方法:查詢返回list集合
	<select id="selectAllAuthorsLinkedList" resultType="org.apache.ibatis.domain.blog.Author">
		select * from author
	</select>
//10、mapper接口方法:查詢返回數組
	<select id="selectAllAuthorsArray" resultType="org.apache.ibatis.domain.blog.Author">
		select * from author
	</select>
//11、mapper接口方法:查詢只返回部分參數
	<select id="selectAuthorLinkedHashMap" resultType="java.util.LinkedHashMap">
		select id, username from author where id = #{value}
	</select>
//12、mapper接口方法:查詢綁定外部傳入參數
	<select id="selectAuthor" parameterMap="selectAuthor" resultMap="selectAuthor">
		select id, username, password, email, bio, favourite_section
		from author where id = ?
	</select>
//13、mapper接口方法:查詢指定入參類型的參數
	<select id="selectAuthorWithInlineParams" parameterType="int"
		resultType="org.apache.ibatis.domain.blog.Author">
		select * from author where id = #{id}
	</select>
//14、mapper接口方法:插入實體對象映射
	<insert id="insertAuthor" parameterType="org.apache.ibatis.domain.blog.Author">
		insert into Author (id,username,password,email,bio)
		values (#{id},#{username},#{password},#{email},#{bio})
	</insert>
//15、mapper接口方法:更新實體對象映射
	<update id="updateAuthor" parameterType="org.apache.ibatis.domain.blog.Author">
		update Author
		set username=#{username,
		javaType=String},
		password=#{password},
		email=#{email},
		bio=#{bio}
		where id=#{id}
	</update>
//16、mapper接口方法:刪除實體根據主鍵ID
	<delete id="deleteAuthor" parameterType="int">
		delete from Author where id = #{id}
	</delete>

//17、mapper接口方法:有選擇更新字段
	<update id="updateAuthorIfNecessary" parameterType="org.apache.ibatis.domain.blog.Author">
		update Author
		<set>
			<if test="username != null">username=#{username},</if>
			<if test="password != null">password=#{password},</if>
			<if test="email != null">email=#{email},</if>
			<if test="bio != null">bio=#{bio}</if>
		</set>
		where id=#{id}
	</update>
//18、mapper接口方法:根據指定的條件進行查詢
	<select id="selectWithOptions" resultType="org.apache.ibatis.domain.blog.Author"
		fetchSize="200" timeout="10" statementType="PREPARED" resultSetType="SCROLL_SENSITIVE" flushCache="false" useCache="false">
		select * from author
	</select>
</mapper>

3.1.3、代碼中XML的配置解析使用示例

3.1.3.1、從 XML 中構建 SqlSessionFactory

根據Mybatis核心設計圖其實可以觀察到,整個Mybatis的核心在於一個SqlSession的一系列操作:實體對象和SQL的綁定,執行會話,結果集處理。而SqlSession的管理則來自於SqlSessionFactory,SqlSessionFactory是可以通過SqlSessionFactoryBuilder獲得構建。如何構建出符合用戶的SqlSessionFactory,則依賴於我們上面提到的Configuration 實例(Mybatis-config.xml)。

⚠️:強調下重點:每個基於 MyBatis 的應用都是以一個 SqlSessionFactory 的實例爲核心的,SqlSessionFactory 的實例是通過SqlSessionFactoryBuilder從Configuration 實例(Mybatis-config.xml)構建出來的。

​ 從 XML 文件中構建 SqlSessionFactory 的實例非常簡單,可以使用類路徑下的資源文件進行配置。也可以使用任意的輸入流(InputStream)實例,比如用文件路徑字符串或 file:// URL 構造的輸入流。MyBatis 包含一個名叫 Resources 的工具類可以通過它來獲取資源輸入流(可以參考之後的源碼明細篇)。

//我們上面3.1.1節提到的配置文件全路徑
String resource = "org/mybatis/example/mybatis-config.xml";
//通過Mybatis提供的Resources工具類獲取輸入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//根據Mybatis提供的SqlSessionFactoryBuilder構建器構建用戶定義的Configuration特有的SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

3.1.3.2、構建我們真正幹活的SqlSession

//SqlSessionFactory 中獲取 SqlSession
 SqlSession sqlSession = sqlSessionFactory.openSession()
 //執行上面我們3.1.2節提到的配置文件mapper中的方法,因爲xml配置好的映射關係所以我們直接是通過sqlSession就可以拿到映射的mapper,怎麼拿到的呢?依然是需要看下第二章中我提到的Mybatis核心設計圖,通過動態代理的方式從Configuration對象中找到對應的mapper,method,parameter。所以從這裏看Configuration就是整個一個倉庫擁有所有你需要的東西。
  //從會話中獲取綁定好的mapper接口信息
    AuthorMapperWithAnnotation mapper = sqlSession.getMapper(AuthorMapperWithAnnotation.class);
    //執行mapper接口的實現方法,而這段具體分析就到第四章和第五章可以學習源碼,第三章主要將全局初始化這個過程。
    Author author = mapper.selectAuthorInfoById(101);

3.2、註解的配置解析示例

3.2.1、Mybatis-config.xml的使用示例

當然這裏也可以使用properties文件屬性等內容,或者springboot的yml文件等配置。

//1、xml的協議約束
<?xml version="1.0" encoding="UTF-8" ?>
//2、Configuration的協議約束
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
//3、全局配置類的約束
<configuration>
    //3.1、全局配置的屬性和事務管理器
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">
                <property name="" value=""/>
            </transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="org.hsqldb.jdbcDriver"/>
                <property name="url" value="jdbc:hsqldb:mem:automapping"/>
                <property name="username" value="sa"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

3.2.2、Mapper接口的使用示例

根據我們接口常用的CRUD操作這裏分別提供了註解的實現方法形式。

public interface AuthorMapperWithAnnotation {
  //使用select註解直接查詢
  @Select("select id, username, password, email, bio, favourite_section from author where id = #{id}")
  Author selectAuthorInfoById(int id);
 //使用SelectProvider註解直接查詢
  @SelectProvider(type =AuthorProvider.class,method = "selectAuthorWithPlaceholder")
  Author selectAuthorWithPlaceholder(Author author);
//使用Insert註解直接查詢
  @Insert("insert into author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio})")
  int insertAuthor(Author author);
//使用InsertProvider註解直接查詢
  @InsertProvider(type =AuthorProvider.class,method = "insertAuthorWithPlaceholder")
  int insertAuthorWithPlaceholder(Author author);
//使用Update註解直接查詢
  @Update("update author set username=#{username} where id =#{id}")
  int updateAuthor(Author author);
//使用UpdateProvider註解直接查詢
  @UpdateProvider(type =AuthorProvider.class,method = "updateAuthorWithPlaceholder")
  void updateAuthorWithPlaceholder(Author author);
//使用Delete註解直接查詢
  @Delete("delete from author where id = #{id}")
  int deleteAuthor(Author author);
//使用DeleteProvider註解直接查詢
  @DeleteProvider(type =AuthorProvider.class,method = "deleteAuthorWithPlaceholder")
  int deleteAuthorWithPlaceholder(Author author);
//提供provider註解類的對應方法
   class AuthorProvider{
     //selectAuthorWithPlaceholder方法
     public String selectAuthorWithPlaceholder(Author author){
       return new SQL(){{
         SELECT("id,username,password,email,bio").FROM("author").WHERE("id=#{id}");
       }}.toString();
     }
     //insertAuthorWithPlaceholder方法
     public String insertAuthorWithPlaceholder(Author author){
       return new SQL(){{
         INSERT_INTO("Author").VALUES("id,username,password,email,bio","#{id},#{username},#{password},#{email},#{bio}");
       }}.toString();
     }
     //updateAuthorWithPlaceholder方法
     public String updateAuthorWithPlaceholder(Author author){
       return new SQL(){{
         UPDATE("Author").SET("id=#{id}","username=#{username}","password=#{password}","email=#{email}","bio=#{bio}").WHERE("id=#{id}");
       }}.toString();
     }
     //deleteAuthorWithPlaceholder方法
     public String deleteAuthorWithPlaceholder(Author author){
       return new SQL(){{
         DELETE_FROM("Author").WHERE("id=#{id}");
       }}.toString();
     }
  }
}

3.3.3、代碼中註解的解析使用示例

//上述提到的輸入流信息我們這裏先以xml爲例子
final String resource = "org/apache/ibatis/builder/Mybatis-config.xml";
final Reader reader = Resources.getResourceAsReader(resource);
//直接代碼構建SqlSessionFactory
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
//初始化全局配置---相當於Mybatis-config.xml中的綁定configuration標籤
    Configuration configuration = new Configuration(sqlMapper.getConfiguration().getEnvironment());
//爲全局配置添加需要的Mapper接口---相當於Mybatis-config.xml中的綁定Mapper.xml文件的標籤
    configuration.addMapper(AuthorMapperWithAnnotation.class);
    //創建SQL會話工廠---利用SqlSessionFactory實現Bean實例化
    SqlSessionFactory sqlMapperWithAnnotation = new DefaultSqlSessionFactory(configuration);
    //獲取SQL會話鏈接---所有Mybatis的核心API接口
    SqlSession sqlSession =  sqlMapperWithAnnotation.openSession();
    //從會話中獲取綁定好的mapper接口信息---利用反射獲取對應的mapper
    AuthorMapperWithAnnotation mapper = sqlSession.getMapper(AuthorMapperWithAnnotation.class);
    //執行插入會話---Mybatis核心設計圖中動態代理執行過程(這裏的源碼分析可以參考第四章、第五章)
    Author expected = new Author(500, "wolf:\"test\"", "******", "[email protected]", "Something...", null);
    mapper.insertAuthorWithPlaceholder(expected);

3.3、核心類和核心方法

  • SqlSessionFactoryBuilder:SqlSessionFactory的構造器,可以自己解析配置,也可以通過提前構建好的配置對象構建。
  • SqlSessionFactory:管理數據庫會話、聚合Configuration的屬性。
  • Configuration:是全局所有的運行數據配置,相當於一個大的倉庫。
  • XMLConfigBuilder:解析XML的Configuration構建器。
  • XMLMapperBuilder:解析XML的Mapper構建器。

根據時序圖我們可以看到實際上分爲三個過程【創建】-》【解析】-》【構建】

3.3.1、SqlSessionFactoryBuilder源碼分析

public class SqlSessionFactoryBuilder {
  //根據字符流構建會話工廠
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
 ...省略本次無關內容...
  //根據字符流和環境和屬性構建會話工廠
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      //利用xml配置構建器
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
   ...省略本次無關內容...
     
  //根據全局配置構建會話工廠,走默認的會話工廠
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

}

3.3.2、SqlSessionFactory源碼分析

3.3.2.1、SqlSessionFactory源碼分析

/*
 *從連接或數據源創建SqlSession
 */
public interface SqlSessionFactory {
  //打開會話
  SqlSession openSession();
  //打開會話是否自動提交
  SqlSession openSession(boolean autoCommit);
  //打開鏈接的session
  SqlSession openSession(Connection connection);
  //打開事務隔離級別的session
  SqlSession openSession(TransactionIsolationLevel level);
  //打開執行器類型的session
  SqlSession openSession(ExecutorType execType);
  //打開執行器類型,是否自動提交的session
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  //打開執行器和事務隔離級別機制的session
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  //打開執行器,鏈接的session
  SqlSession openSession(ExecutorType execType, Connection connection);
  //獲取全局配置
  Configuration getConfiguration();

}

3.3.2.2、DefaultSqlSessionFactory源碼分析


/**
 * 默認的會話工廠
 * @author Clinton Begin
 */
public class DefaultSqlSessionFactory implements SqlSessionFactory {
  //全局配置
  private final Configuration configuration;
  //構造函數
  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }
  
...省略本次無關內容...
}

3.3.3、Configuration源碼分析


/**
 * 抽象構建器
 * @author Clinton Begin
 */
public abstract class BaseBuilder {
  //全局配置
  protected final Configuration configuration;
  //類型別名註冊器
  protected final TypeAliasRegistry typeAliasRegistry;
  //類型處理器註冊器
  protected final TypeHandlerRegistry typeHandlerRegistry;
  //構造函數
  public BaseBuilder(Configuration configuration) {
    this.configuration = configuration;
    this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
    this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
  }
  //獲取全局配置
  public Configuration getConfiguration() {
    return configuration;
  }
  //解析正則表達式
  protected Pattern parseExpression(String regex, String defaultValue) {
    return Pattern.compile(regex == null ? defaultValue : regex);
  }
  //獲取boolean值
  protected Boolean booleanValueOf(String value, Boolean defaultValue) {
    return value == null ? defaultValue : Boolean.valueOf(value);
  }
  //獲取int值
  protected Integer integerValueOf(String value, Integer defaultValue) {
    return value == null ? defaultValue : Integer.valueOf(value);
  }
  //獲取set值
  protected Set<String> stringSetValueOf(String value, String defaultValue) {
    value = value == null ? defaultValue : value;
    return new HashSet<>(Arrays.asList(value.split(",")));
  }
  //解析jdbc類型
  protected JdbcType resolveJdbcType(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return JdbcType.valueOf(alias);
    } catch (IllegalArgumentException e) {
      throw new BuilderException("Error resolving JdbcType. Cause: " + e, e);
    }
  }
  //解析結果集類型
  protected ResultSetType resolveResultSetType(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return ResultSetType.valueOf(alias);
    } catch (IllegalArgumentException e) {
      throw new BuilderException("Error resolving ResultSetType. Cause: " + e, e);
    }
  }
  //解析參數風格
  protected ParameterMode resolveParameterMode(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return ParameterMode.valueOf(alias);
    } catch (IllegalArgumentException e) {
      throw new BuilderException("Error resolving ParameterMode. Cause: " + e, e);
    }
  }
  //創建實例
  protected Object createInstance(String alias) {
    Class<?> clazz = resolveClass(alias);
    if (clazz == null) {
      return null;
    }
    try {
      return clazz.getDeclaredConstructor().newInstance();
    } catch (Exception e) {
      throw new BuilderException("Error creating instance. Cause: " + e, e);
    }
  }
  //根據別名解析類
  protected <T> Class<? extends T> resolveClass(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return resolveAlias(alias);
    } catch (Exception e) {
      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
  }
  //解析類型處理器
  protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, String typeHandlerAlias) {
    if (typeHandlerAlias == null) {
      return null;
    }
    Class<?> type = resolveClass(typeHandlerAlias);
    if (type != null && !TypeHandler.class.isAssignableFrom(type)) {
      throw new BuilderException("Type " + type.getName() + " is not a valid TypeHandler because it does not implement TypeHandler interface");
    }
    @SuppressWarnings("unchecked") // already verified it is a TypeHandler
    Class<? extends TypeHandler<?>> typeHandlerType = (Class<? extends TypeHandler<?>>) type;
    return resolveTypeHandler(javaType, typeHandlerType);
  }
  //解析類型處理器
  protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, Class<? extends TypeHandler<?>> typeHandlerType) {
    if (typeHandlerType == null) {
      return null;
    }
    // javaType ignored for injected handlers see issue #746 for full detail
    TypeHandler<?> handler = typeHandlerRegistry.getMappingTypeHandler(typeHandlerType);
    if (handler == null) {
      // not in registry, create a new one
      handler = typeHandlerRegistry.getInstance(javaType, typeHandlerType);
    }
    return handler;
  }
  //解析別名
  protected <T> Class<? extends T> resolveAlias(String alias) {
    return typeAliasRegistry.resolveAlias(alias);
  }
}

3.3.4.1、XMLConfigBuilder源碼分析

/**
 * xml配置構建器
 * @author Clinton Begin
 * @author Kazuki Shimizu
 */
public class XMLConfigBuilder extends BaseBuilder {
  //是否解析
  private boolean parsed;
  //解析器
  private final XPathParser parser;
  //環境
  private String environment;
  //本地反射工廠
  private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
  //構造函數
  public XMLConfigBuilder(Reader reader) {
    this(reader, null, null);
  }
  //構造函數
  public XMLConfigBuilder(Reader reader, String environment) {
    this(reader, environment, null);
  }
  //構造函數
  public XMLConfigBuilder(Reader reader, String environment, Properties props) {
    this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
  }
  //構造函數
  public XMLConfigBuilder(InputStream inputStream) {
    this(inputStream, null, null);
  }
  //構造函數
  public XMLConfigBuilder(InputStream inputStream, String environment) {
    this(inputStream, environment, null);
  }
   //構造函數
  public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
    this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
  }
   //私有構造函數
  private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }
  //解析全局配置對象
  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"));
      //解析setting節點字段
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      //加載用戶自定義的VFS解析文件類
      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"));
      //數據庫ID
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //類型處理器元素
      typeHandlerElement(root.evalNode("typeHandlers"));
      //mapper接口元素
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }
  //設置屬性
  private Properties settingsAsProperties(XNode context) {
    if (context == null) {
      return new Properties();
    }
    Properties props = context.getChildrenAsProperties();
    //檢查所有的setting設置是在配置類中已知的
    // Check that all settings are known to the configuration class
    MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
    for (Object key : props.keySet()) {
      if (!metaConfig.hasSetter(String.valueOf(key))) {
        throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
      }
    }
    return props;
  }
   //加載定製vfs解析實現類
  private void loadCustomVfs(Properties props) throws ClassNotFoundException {
    String value = props.getProperty("vfsImpl");
    if (value != null) {
      String[] clazzes = value.split(",");
      for (String clazz : clazzes) {
        if (!clazz.isEmpty()) {
          @SuppressWarnings("unchecked")
          Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
          configuration.setVfsImpl(vfsImpl);
        }
      }
    }
  }
  //加載定製實現類
  private void loadCustomLogImpl(Properties props) {
    Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
    configuration.setLogImpl(logImpl);
  }
  //類型別名元素
  private void typeAliasesElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String typeAliasPackage = child.getStringAttribute("name");
          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
        } else {
          String alias = child.getStringAttribute("alias");
          String type = child.getStringAttribute("type");
          try {
            Class<?> clazz = Resources.classForName(type);
            if (alias == null) {
              typeAliasRegistry.registerAlias(clazz);
            } else {
              typeAliasRegistry.registerAlias(alias, clazz);
            }
          } catch (ClassNotFoundException e) {
            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
          }
        }
      }
    }
  }
 //插件元素
  private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        Properties properties = child.getChildrenAsProperties();
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
        interceptorInstance.setProperties(properties);
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }
  //對象工廠元素
  private void objectFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties properties = context.getChildrenAsProperties();
      ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(properties);
      configuration.setObjectFactory(factory);
    }
  }
  //對象包裝工廠元素
  private void objectWrapperFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      configuration.setObjectWrapperFactory(factory);
    }
  }
  //反射工廠元素
  private void reflectorFactoryElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      configuration.setReflectorFactory(factory);
    }
  }
//屬性元素
  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.  Please specify one or the other.");
      }
      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);
    }
  }
  //設置屬性
  private void settingsElement(Properties props) {
    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
    configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
    configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
    configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
    configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
    configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
    configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
    configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
    configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
    configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
    configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
    configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
    configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
    configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
    configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
    configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
    configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
    configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
    configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
    configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
    configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
    configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
    configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
    configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
    configuration.setLogPrefix(props.getProperty("logPrefix"));
    configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
  }
  //環境元素
  private void environmentsElement(XNode context) throws Exception {
    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"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }
  //數據庫ID服務元素
  private void databaseIdProviderElement(XNode context) throws Exception {
    DatabaseIdProvider databaseIdProvider = null;
    if (context != null) {
      String type = context.getStringAttribute("type");
      // awful patch to keep backward compatibility
      if ("VENDOR".equals(type)) {
        type = "DB_VENDOR";
      }
      Properties properties = context.getChildrenAsProperties();
      databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
      databaseIdProvider.setProperties(properties);
    }
    Environment environment = configuration.getEnvironment();
    if (environment != null && databaseIdProvider != null) {
      String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
      configuration.setDatabaseId(databaseId);
    }
  }
  //事務處理的元素
  private TransactionFactory transactionManagerElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a TransactionFactory.");
  }
  //數據源處理的元素
  private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(props);
      return factory;
    }
    throw new BuilderException("Environment declaration requires a DataSourceFactory.");
  }
  //類型處理器的元素
  private void typeHandlerElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String typeHandlerPackage = child.getStringAttribute("name");
          typeHandlerRegistry.register(typeHandlerPackage);
        } else {
          String javaTypeName = child.getStringAttribute("javaType");
          String jdbcTypeName = child.getStringAttribute("jdbcType");
          String handlerTypeName = child.getStringAttribute("handler");
          Class<?> javaTypeClass = resolveClass(javaTypeName);
          JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
          Class<?> typeHandlerClass = resolveClass(handlerTypeName);
          if (javaTypeClass != null) {
            if (jdbcType == null) {
              typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
            } else {
              typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
            }
          } else {
            typeHandlerRegistry.register(typeHandlerClass);
          }
        }
      }
    }
  }
  //mapper文件解析元素
  private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
          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);
            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);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null && mapperClass != null) {
            Class<?> mapperInterface = Resources.classForName(mapperClass);
            configuration.addMapper(mapperInterface);
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }
  //是否指定環境
  private boolean isSpecifiedEnvironment(String id) {
    if (environment == null) {
      throw new BuilderException("No environment specified.");
    } else if (id == null) {
      throw new BuilderException("Environment requires an id attribute.");
    } else if (environment.equals(id)) {
      return true;
    }
    return false;
  }

}

3.3.4.2、XMLMapperBuilder源碼分析

/**
 * XML的mapper接口構建器
 */
public class XMLMapperBuilder extends BaseBuilder {
  //解析器
  private final XPathParser parser;
  //接口助手
  private final MapperBuilderAssistant builderAssistant;
  //sql節點片段
  private final Map<String, XNode> sqlFragments;
  //資源
  private final String resource;
  //不建議使用,未來廢棄
  @Deprecated
  public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
    this(reader, configuration, resource, sqlFragments);
    this.builderAssistant.setCurrentNamespace(namespace);
  }
  //不建議使用,未來廢棄
  @Deprecated
  public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
        configuration, resource, sqlFragments);
  }
  //構造函數
  public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
    this(inputStream, configuration, resource, sqlFragments);
    this.builderAssistant.setCurrentNamespace(namespace);
  }
  //構造函數
  public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
        configuration, resource, sqlFragments);
  }
   //構造函數
  private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    super(configuration);
    this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
    this.parser = parser;
    this.sqlFragments = sqlFragments;
    this.resource = resource;
  }
  //解析mapper
  public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      //將mapper和命名空間綁定
      bindMapperForNamespace();
    }
    //解析等待的結果映射
    parsePendingResultMaps();
    //解析等待的緩存引用
    parsePendingCacheRefs();
    //解析等待的會話
    parsePendingStatements();
  }
  //獲取sql片段根據引用ID
  public XNode getSqlFragment(String refid) {
    return sqlFragments.get(refid);
  }
  //配置全局配置
  private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      //綁定當前的命名空間
      builderAssistant.setCurrentNamespace(namespace);
      //緩存引用
      cacheRefElement(context.evalNode("cache-ref"));
      //緩存
      cacheElement(context.evalNode("cache"));
      //參數map
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //結果map
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //sql
      sqlElement(context.evalNodes("/mapper/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);
    }
  }
  //構建會話從上下文
  private void buildStatementFromContext(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      buildStatementFromContext(list, configuration.getDatabaseId());
    }
    buildStatementFromContext(list, null);
  }
  //構建會話從上下文
  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }
  //解析等待的結果映射
  private void parsePendingResultMaps() {
    Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
    synchronized (incompleteResultMaps) {
      Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
      while (iter.hasNext()) {
        try {
          iter.next().resolve();
          iter.remove();
        } catch (IncompleteElementException e) {
          // ResultMap is still missing a resource...
        }
      }
    }
  }
  //解析等待的緩存引用
  private void parsePendingCacheRefs() {
    Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
    synchronized (incompleteCacheRefs) {
      Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
      while (iter.hasNext()) {
        try {
          iter.next().resolveCacheRef();
          iter.remove();
        } catch (IncompleteElementException e) {
          // Cache ref is still missing a resource...
        }
      }
    }
  }
  //解析等待的會話
  private void parsePendingStatements() {
    Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
    synchronized (incompleteStatements) {
      Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
      while (iter.hasNext()) {
        try {
          iter.next().parseStatementNode();
          iter.remove();
        } catch (IncompleteElementException e) {
          // Statement is still missing a resource...
        }
      }
    }
  }
  //緩存引用元素
  private void cacheRefElement(XNode context) {
    if (context != null) {
      configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
      CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
      try {
        cacheRefResolver.resolveCacheRef();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteCacheRef(cacheRefResolver);
      }
    }
  }
  //緩存元素
  private void cacheElement(XNode context) {
    if (context != null) {
      String type = context.getStringAttribute("type", "PERPETUAL");
      Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
      String eviction = context.getStringAttribute("eviction", "LRU");
      Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
      Long flushInterval = context.getLongAttribute("flushInterval");
      Integer size = context.getIntAttribute("size");
      boolean readWrite = !context.getBooleanAttribute("readOnly", false);
      boolean blocking = context.getBooleanAttribute("blocking", false);
      Properties props = context.getChildrenAsProperties();
      builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
    }
  }
  //參數映射元素
  private void parameterMapElement(List<XNode> list) {
    for (XNode parameterMapNode : list) {
      String id = parameterMapNode.getStringAttribute("id");
      String type = parameterMapNode.getStringAttribute("type");
      Class<?> parameterClass = resolveClass(type);
      List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
      List<ParameterMapping> parameterMappings = new ArrayList<>();
      for (XNode parameterNode : parameterNodes) {
        String property = parameterNode.getStringAttribute("property");
        String javaType = parameterNode.getStringAttribute("javaType");
        String jdbcType = parameterNode.getStringAttribute("jdbcType");
        String resultMap = parameterNode.getStringAttribute("resultMap");
        String mode = parameterNode.getStringAttribute("mode");
        String typeHandler = parameterNode.getStringAttribute("typeHandler");
        Integer numericScale = parameterNode.getIntAttribute("numericScale");
        ParameterMode modeEnum = resolveParameterMode(mode);
        Class<?> javaTypeClass = resolveClass(javaType);
        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
        Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
        ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
        parameterMappings.add(parameterMapping);
      }
      builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
    }
  }
  //結果映射
  private void resultMapElements(List<XNode> list) throws Exception {
    for (XNode resultMapNode : list) {
      try {
        resultMapElement(resultMapNode);
      } catch (IncompleteElementException e) {
        // ignore, it will be retried
      }
    }
  }
  //結果映射
  private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
    return resultMapElement(resultMapNode, Collections.emptyList(), null);
  }
  //結果映射
  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception {
    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
    String type = resultMapNode.getStringAttribute("type",
        resultMapNode.getStringAttribute("ofType",
            resultMapNode.getStringAttribute("resultType",
                resultMapNode.getStringAttribute("javaType"))));
    Class<?> typeClass = resolveClass(type);
    if (typeClass == null) {
      typeClass = inheritEnclosingType(resultMapNode, enclosingType);
    }
    Discriminator discriminator = null;
    List<ResultMapping> resultMappings = new ArrayList<>();
    resultMappings.addAll(additionalResultMappings);
    List<XNode> resultChildren = resultMapNode.getChildren();
    for (XNode resultChild : resultChildren) {
      if ("constructor".equals(resultChild.getName())) {
        processConstructorElement(resultChild, typeClass, resultMappings);
      } else if ("discriminator".equals(resultChild.getName())) {
        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
      } else {
        List<ResultFlag> flags = new ArrayList<>();
        if ("id".equals(resultChild.getName())) {
          flags.add(ResultFlag.ID);
        }
        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
      }
    }
    String id = resultMapNode.getStringAttribute("id",
            resultMapNode.getValueBasedIdentifier());
    String extend = resultMapNode.getStringAttribute("extends");
    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    try {
      return resultMapResolver.resolve();
    } catch (IncompleteElementException  e) {
      configuration.addIncompleteResultMap(resultMapResolver);
      throw e;
    }
  }
  //繼承封裝類型
  protected Class<?> inheritEnclosingType(XNode resultMapNode, Class<?> enclosingType) {
    if ("association".equals(resultMapNode.getName()) && resultMapNode.getStringAttribute("resultMap") == null) {
      String property = resultMapNode.getStringAttribute("property");
      if (property != null && enclosingType != null) {
        MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());
        return metaResultType.getSetterType(property);
      }
    } else if ("case".equals(resultMapNode.getName()) && resultMapNode.getStringAttribute("resultMap") == null) {
      return enclosingType;
    }
    return null;
  }
  //執行構造元素
  private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
    List<XNode> argChildren = resultChild.getChildren();
    for (XNode argChild : argChildren) {
      List<ResultFlag> flags = new ArrayList<>();
      flags.add(ResultFlag.CONSTRUCTOR);
      if ("idArg".equals(argChild.getName())) {
        flags.add(ResultFlag.ID);
      }
      resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
    }
  }
  //執行鑑別器元素
  private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
    String column = context.getStringAttribute("column");
    String javaType = context.getStringAttribute("javaType");
    String jdbcType = context.getStringAttribute("jdbcType");
    String typeHandler = context.getStringAttribute("typeHandler");
    Class<?> javaTypeClass = resolveClass(javaType);
    Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
    Map<String, String> discriminatorMap = new HashMap<>();
    for (XNode caseChild : context.getChildren()) {
      String value = caseChild.getStringAttribute("value");
      String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings, resultType));
      discriminatorMap.put(value, resultMap);
    }
    return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
  }
  //sql元素
  private void sqlElement(List<XNode> list) {
    if (configuration.getDatabaseId() != null) {
      sqlElement(list, configuration.getDatabaseId());
    }
    sqlElement(list, null);
  }
  //sql元素
  private void sqlElement(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
      String databaseId = context.getStringAttribute("databaseId");
      String id = context.getStringAttribute("id");
      id = builderAssistant.applyCurrentNamespace(id, false);
      if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
        sqlFragments.put(id, context);
      }
    }
  }
  //數據庫ID匹配當前要求
  private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
    if (requiredDatabaseId != null) {
      return requiredDatabaseId.equals(databaseId);
    }
    if (databaseId != null) {
      return false;
    }
    if (!this.sqlFragments.containsKey(id)) {
      return true;
    }
    // skip this fragment if there is a previous one with a not null databaseId
    XNode context = this.sqlFragments.get(id);
    return context.getStringAttribute("databaseId") == null;
  }
  //從上下文構建結果映射
  private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
    String property;
    if (flags.contains(ResultFlag.CONSTRUCTOR)) {
      property = context.getStringAttribute("name");
    } else {
      property = context.getStringAttribute("property");
    }
    String column = context.getStringAttribute("column");
    String javaType = context.getStringAttribute("javaType");
    String jdbcType = context.getStringAttribute("jdbcType");
    String nestedSelect = context.getStringAttribute("select");
    String nestedResultMap = context.getStringAttribute("resultMap",
        processNestedResultMappings(context, Collections.emptyList(), resultType));
    String notNullColumn = context.getStringAttribute("notNullColumn");
    String columnPrefix = context.getStringAttribute("columnPrefix");
    String typeHandler = context.getStringAttribute("typeHandler");
    String resultSet = context.getStringAttribute("resultSet");
    String foreignColumn = context.getStringAttribute("foreignColumn");
    boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
    Class<?> javaTypeClass = resolveClass(javaType);
    Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
    return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
  }
  //執行嵌套結果映射
  private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings, Class<?> enclosingType) throws Exception {
    if ("association".equals(context.getName())
        || "collection".equals(context.getName())
        || "case".equals(context.getName())) {
      if (context.getStringAttribute("select") == null) {
        validateCollection(context, enclosingType);
        ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
        return resultMap.getId();
      }
    }
    return null;
  }
  //校驗集合
  protected void validateCollection(XNode context, Class<?> enclosingType) {
    if ("collection".equals(context.getName()) && context.getStringAttribute("resultMap") == null
        && context.getStringAttribute("javaType") == null) {
      MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());
      String property = context.getStringAttribute("property");
      if (!metaResultType.hasSetter(property)) {
        throw new BuilderException(
          "Ambiguous collection type for property '" + property + "'. You must specify 'javaType' or 'resultMap'.");
      }
    }
  }
  //構建命名空間的mapper
  private void bindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        //ignore, bound type is not required
      }
      if (boundType != null) {
        if (!configuration.hasMapper(boundType)) {
         
          configuration.addLoadedResource("namespace:" + namespace);
          configuration.addMapper(boundType);
        }
      }
    }
  }

}

Mybatis構建加載初始化源碼分析這節到這裏就結束了,可以再回顧下核心重點圖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章