今天來分析Configuration初始化的最後一部分mapper的加載。程序員
加載方法mapperElement
XMLConfigBuilder配置Configuration的parseConfiguration方法還剩最後一行解析代碼:mapperElement(root.evalNode("mappers"));mybatis
mapperElement方法源碼與詳解以下圖:app
從源碼能夠得出一些結論:學習
mappers節點支持mapper和package兩種類型子節點;ui
package子節點只須要name一個屬性;url
一個mapper子節點有且只能有url、resource、class三個屬性中其中一個,不然會拋出異常;spa
mapperElement解析兩種mappers子節點,主要代碼我分紅了4個部分,接下來逐一進行深刻解析。3d
解析包方法addMappers
首先來看解析包的方法使用的是configuration的addMappers方法,方法主要是涉及到一個MapperRegistry類型的屬性mapperRegistry,addMappers主要流程以下圖:代理
addMappers方法主要涉及到的是MapperRegistry這個類,這個類有兩個屬性:config、knownMappers。在config指向的是configuration,knownMappers存放這class文件對應的MapperProxyFactory。MapperProxyFactory根據名字先猜想是建立mapper代理的工廠。xml
介紹完關鍵類,再來看addMappers主要分4步:
調用mapperRegistry屬性的addMappers(String packageName)方法這個方法會調用另一個addMappers;
addMappers(String packageName, Class<?> superType)方法會遍歷指定包下面全部屬於superType子類的類,上一步傳遞的是Object.class,因此這裏是遍歷全部類,而後調用addMapper(mapperClass)方法;
addMapper(mapperClass)方法首先須要判斷mapperClass必須是接口,再判斷class是否已經存在,存在會報異常。不存在則實例化一個MapperProxyFactory對象並put進knownMappers,最後根據class建立一個MapperAnnotationBuilder並調用parse方法。
最後是MapperAnnotationBuilder的parse方法,MapperAnnotationBuilder是解析mapper註解的,咱們後面詳解。
加載package下的mapper總的流程看下來比較簡單,實際上就是找到對應包下面全部的接口,而後根據接口建立一個MapperProxyFactory放到configuration屬性mapperRegistry的knownMappers中。
解析單個mapper
從解析單個mapper有三種狀況,可是分兩種狀況,一種是有resource或者url屬性的是直接根據屬性值生成一個XMLMapperBuilder對象,而後執行parse方法,若是是由class屬性值和加載包的最後一步方法類似,調用mapperRegistry的addMapper方法。
XMLMapperBuilder的初始化和parse簡單介紹源碼以下圖:
解析mapper.xml的XMLMapperBuilder和最開始解析mybatis-config.xml的XMLConfigBuilder同樣都是繼承至mybatis的BaseBuilder,而且初始化流程也差很少。
能夠看出XMLMapperBuilder類是解析mapper.xml最關鍵的類,這個類比較複雜,接下來的文章再來專門講解它。
總結
mapper的注入支持兩種方式,單個mapper注入或者整個包下面注入,也能夠按加載class文件或者xml文件分紅兩種。單個mapper注入若是是根據url或者xml則是經過加載xml文件注入,經過url獲取掃描整個包加載則是class方式進行注入。
經過xml加載是直接根據xml生成XMLMapperBuilder,而後執行parse方法。
經過class加載則是接口類生成MapperProxyFactory,放到MapperRegistry的map屬性knownMappers中,最後經過MapperAnnotationBuilder執行parse進行解析,parse也會調用XMLMapperBuilder的parse方法。
後面的文章咱們先解讀MapperAnnotationBuilder這個類,最終再來看最重要的類XMLMapperBuilder。
從目前源碼能夠得出一些須要注意的點:
一個mapper子節點有且只能有url、resource、class三個屬性中其中一個,不然會拋出異常;
一個mapper只能被加載一次,重複加載會拋出異常。
Java程序員平常學習筆記,如理解有誤歡迎各位交流討論!