mybatis源碼分析-映射文件解析

mybatis源碼分析-配置文件解析過程 一文中,主要對配置文件解析過程作了講解,而且針對插件的配置文件作了詳細講解,本文主要對 mapper 映射文件的解析進行講解。segmentfault

mapper文件的加載

首先咱們看下mybatis官網,看下mapper文件如何被全局配置文件加載的。下面是官網的說明:緩存


既然 MyBatis 的行爲已經由上述元素配置完了,咱們如今就要定義 SQL 映射語句了。 可是首先咱們須要告訴 MyBatis 到哪裏去找到這些語句。 Java 在自動查找這方面沒有提供一個很好的方法,因此最佳的方式是告訴 MyBatis 到哪裏去找映射文件。 你可使用相對於類路徑的資源引用, 或徹底限定資源定位符(包括file:///的 URL),或類名和包名等。例如:mybatis

<!-- 使用相對於類路徑的資源引用 -->  
<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>

上面是mybatis所支持的mapper文件的編寫方式,咱們下面從源碼角度研究一下。app

mapper文件解析源碼

首先了解一點,咱們須要把接口所有加載到 MapperRegistry 類中,使用map保存。源碼分析

private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();

這個 MapperRegistry 類暫時不講,之後會詳細講解。只要知道 Configuration 類有 addMapper 方法能夠把接口加入到上面的 map 中便可。下面看具體源碼:ui

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.");  
                }  
            }  
        }  
    }  
}
  • ①若是配置文件使用的是使用 package 方式,須要把該包下面的全部接口都存入 map 中。
  • ②若是配置是resource方式,則獲取到 mapper 映射文件的路徑,而後解析這些文件,注意解析生成的是 XMLMapperBuilder 對象,而不是 XMLConfigBuilder 對象。XMLMapperBuilder 對象的parse方法就能夠進行將mapper文件進行解析。
  • ③若是配置是url方式,同 resource。
  • ④若是配置的是 class ,那麼直接存入 map ,無需解析。這種方式使用 mapper 接口替代 mapper映射文件的配置方式。

上面無論使用什麼方式,都須要在加載全局配置文件的時候,將咱們所定義的接口先緩存起來,以便後面接口的調用。可是上面4種配置方式大體能夠分爲 2 種,一種直接找 mapper xml 配置文件,一種是找接口或者包(包其實下面也是接口)。url

本節暫時不講解那麼多,後面章節主要講解這兩種方式。不過能夠首先透漏下:spa

  • 對於 接口或者包 的形式,主要講解的代碼是

image.png

  • 對於其它兩種方式
    主要是 XMLMapperBuilder 的研究。
相關文章
相關標籤/搜索