MyBatis 源碼學習6——SqlSession執行Mapper過程(上)

Mapper由兩部分組成:Mapper接口和通過註解或者XML文件配置的SQL語句。

SqlSession執行Mapper過程主要分爲4個階段
在這裏插入圖片描述

1.Mapper接口的註冊過程,
2.MappedStatement對象的註冊過程,
3.Mapper方法的調用過程,
4.SqlSession執行Mapper的過程。

一、Mapper接口的註冊過程

Mapper接口:定義執行SQL語句相關的方法,方法名一般和Mapper XML配置文件中<select|update|delete|insert>標籤的id屬性相同,接口的完全限定名一般對應Mapper XML配置文件的命名空間。

執行Mapper中定義的方法

1.在創建SqlSession實例後,需要調用SqlSession的getMapper()方法獲取一個Mapper的引用,即一個MapperProxy的實例。
在這裏插入圖片描述

注意:接口中定義的方法必須通過某個類實現該接口,然後創建該類的實例,再通過實例調用方法,所以SqlSession對象的getMapper()方法返回的一定是一個動態代理對象。

2.然後通過該引用調用Mapper接口中定義的方法。

SqlSession對象getMapper()方法的實現:configuration.getMapper(type, this)

再查看Configuration對象的getMapper()方法,其實現:
mapperRegistry.getMapper(type, sqlSession);

在這裏插入圖片描述

要看懂上面的代碼,先了解下Configuration類的屬性類MapperRegistry mapperRegistry
在這裏插入圖片描述

MapperRegistry類有一個變量Map<Class<?>, MapperProxyFactory<?>> knownMappers
用於註冊Mapper接口對應的Class對象和MapperProxyFactory對象之間的關係。

MapperRegistry類提供了addMapper()方法
用於向knownMappers屬性中註冊Mapper接口信息,MyBatis框架在應用啓動時會解析所有的Mapper接口,然後調用此方法。

在addMapper()方法中,每個Mapper接口爲對應的Class對象創建一個MapperProxyFactory對象,然後添加到knownMappers屬性中。

MapperRegistry類提供了getMapper()方法
能夠根據Mapper接口的Class對象獲取對應的MapperProxyFactory,然後就可以使用MapperProxyFactory對象調用方法newInstance(SqlSession sqlSession)創建Mapper動態代理對象了。
在這裏插入圖片描述

注意:
Java語言中比較常用的實現動態代理的方式有兩種,即JDK內置動態代理和CGLIB動態代理。

MyBatis中通過MapperProxy類實現動態代理,使用的是JDK內置的動態代理,MapperProxy類實現了InvocationHandler接口,invoke()方法中爲通用的攔截邏輯。

使用JDK內置動態代理,通過MapperProxy類實現InvocationHandler接口,定義方法執行攔截邏輯後,還需要調用java.lang.reflect.Proxy類的newProxyInstance()方法創建代理對象。

二、Mapper SQL配置信息,即MappedStatement註冊過程

MyBatis通過MappedStatement類描述Mapper的SQL配置信息,其中SQL配置有兩種方式:
一種是通過XML文件配置;另一種是通過Java註解。
在這裏插入圖片描述

先了解下Configuration類的屬性Map<String, MappedStatement> mappedStatements
用於註冊MyBatis中所有的MappedStatement對象,其中
Key:Mapper SQL配置的Id,如果SQL是通過XML配置的,則Id爲命名空間加上<select|update|delete|insert>標籤的Id,如果SQL通過Java註解配置,則Id爲Mapper接口的完全限定名(包括包名)加上方法名稱

Configuration類中提供了addMappedStatement()方法:將MappedStatement對象添加到mappedStatements屬性中。
在這裏插入圖片描述

下面開始詳解MyBatis中Mapper SQL配置信息(MappedStatement對象)的註冊過程,即MappedStatement對象的創建及註冊過程:
Configuration對象創建過程中,通過XMLConfigBuilder對象來解析MyBatis主配置文件,其**parseConfiguration()**方法中會調用mapperElement(root.evalNode(“mappers”))解析<mappers>標籤。

詳細看下mapperElement()方法的實現:
在這裏插入圖片描述
1.首先通過root.evalNode(“mappers”)獲取<mappers>所有子標籤(<mapper>標籤或<package>標籤)。

2.因爲<mappers>標籤配置Mapper信息有以下幾種方式,所以mapperElement()方法中對這幾種情形的配置分別做了處理,接下來以<mapper resource="……"/>這種形式爲例介紹Mapper SQL配置文件的解析過程。

3.根據resonrce中的地址找到Mapper接口,以Mapper接口的輸入流作爲參數,創建一個XMLMapperBuilder對象 。

4.調用XMLMapperBuilder對象的parse()方法完成解析

詳細看下parse()方法的實現:
在這裏插入圖片描述

1.首先調用XPathParser對象的evalNode()方法獲取根節點對應的XNode對象

2.接着調用configurationElement()方法對Mapper配置內容做進一步解析。

configurationElement()方法中,對Mapper SQL配置文件的所有標籤進行解析,這裏重點關注<select|insert|update|delete>標籤的解析過程:
在這裏插入圖片描述

1.獲取<select|insert|update|delete>標籤節點對應的XNode對象後,

2.調用XMLMapperBuilder類的buildStatementFromContext()方法做進一步解析處理。

buildStatementFromContext()方法的實現:
在這裏插入圖片描述
1.遍歷所有XNode對象,爲每個<select|insert|update|delete>標籤對應的XNode對象創建一個XMLStatementBuilder對象,

2.接着調用XMLStatementBuilder對象的parseStatementNode()方法進行解析處理。

XMLStatementBuilder類的parseStatementNode()方法的實現:

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

1.獲取<select|insert|delete|update>標籤的所有屬性信息。

2.將<include>標籤引用的SQL片段替換爲對應的<sql>標籤中定義的內容。

3.獲取lang屬性指定的LanguageDriver,通過LanguageDriver創建SqlSource。MyBatis中的SqlSource表示一個SQL資源。

4.獲取KeyGenerator對象。KeyGenerator的不同實例代表不同的主鍵生成策略。

5.所有解析工作完成後,使用MapperBuilderAssistant對象的addMappedStatement()方法創建MappedStatement對象。創建完成後,調用Configuration對象的addMappedStatement()方法將MappedStatement對象註冊到Configuration對象中。

需要注意的是,MyBatis中的MapperBuilderAssistant是一個輔助工具類,用於構建Mapper相關的對象,例如Cache、ParameterMap、ResultMap等。

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