Mybatis源碼解析-5.Mappers標籤解析

Mappers標籤解析

對於Mybatis來說,Mapper對象提供了主要的持久化功能,因此,這部分實際上是整個框架的主要功能。正是Mapper對象,將XML文件中的配置與Java對象映射起來。本部分,我們開始分析<mappers>標籤的解析。

在Mybatis配置文件中,Mapper相關的配置標籤有兩個,分別是<mappers><mapper>,前者用於配置<mapper>標籤配置文件所在的位置,後者則是真正的Mapper對象映射的內容。下面給出Mybatis文檔中允許的幾種<mappers>標籤配置方式:

<!-- 使用相對於類路徑的資源引用 -->
<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="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</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>

可以看到,對於<mappers>標籤有四種配置方式,其中resource屬性和url屬性都是基於xml文件配置mapper標籤,而後兩種是通過Java註解方式配置mapper標籤。

下面我們開始分析Mybatis如何對這兩類配置進行解析。

解析標籤

XMLConfigBuilder類中,解析<mappers>標籤的工作是由mapperElement(XNode)方法完成的。我們可以考察該方法:

private void mapperElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        if ("package".equals(child.getName())) {
          // 解析Java包中的所有Class文件
          ...
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if (resource != null && url == null && mapperClass == null) {
            // 讀取本地XML文件,進行解析
            ...
          } else if (resource == null && url != null && mapperClass == null) {
            // 讀取url指向的xml文件,進行解析
            ...
          } else if (resource == null && url == null && mapperClass != null) {
            // 解析<mapper>標籤中顯式指定的Class文件
            ...
          } else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }

可以看到,由於mappers標籤有四種配置方式,這裏明顯分出了4中解析方式,但是其實這四種解析方式是兩兩一組的,首先我們可以看一下根據xml文件進行解析的兩種情況,他們都是如下模式:

ErrorContext.instance().resource(url);
// InputStream inputStream = Resources.getResourceAsStream(resource);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();

可以看到,解析XML文件的模式都是獲取xml文件,將其讀取成流,然後交給XMLMapperBuilder進行處理。在之前分析XMLConfigBuilder時,我們就說過BaseBuilder的所有子類中,除了XMLConfigBuilder,都是爲了解析<mapper>標籤服務的,這正是使用了XMLMapperBuilder

而對於Java註解型的配置,解析單個mapper標籤的配置是用如下代碼完成的:

Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);

真正的mapper標籤解析邏輯在Configuration的addMapper(Class<T> type)方法中,實際上,該方法又調用了mapperRegistryaddMapper(Class<T> type)方法:

public <T> void addMapper(Class<T> type) {
  mapperRegistry.addMapper(type);
}

至於mapperRegistry的addMapper(Class<T>)方法的具體邏輯將在下面解析<mapper>標籤時進行討論。

最後,我們需要討論一下mapper標籤提供包名稱的配置解析,其解析代碼如下:

String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);

實際上,Configuration的addMapper(Class<T> type)方法又是調用了mapperRegistryaddMappers(String packageName)方法,該方法用於解析包中,父類是Object類型的類,對其調用addMapper(Class)方法。

public void addMappers(String packageName, Class<?> superType) {
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
    for (Class<?> mapperClass : mapperSet) {
      addMapper(mapperClass);
    }
}

綜上所屬,實際上,對於XML文件格式的mapper標籤的解析,由XMLMapperBuilder進行處理,而對於Java格式的mapper標籤解析是通過MapperRegistryaddMapper(Class<T> type)方法完成的。

至此,mappers標籤的解析邏輯就分析完了,可以看到,其實mappers標籤的解析中,最重要的還是mapper標籤的解析,而這一部分我們將會在後面進行詳細講解mapper配置文件的解析也是mybatis中最複雜的部分,甚至比執行邏輯還複雜,迫不及待了吧。讓我們進入下一節,解析mapper標籤的配置吧。

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