在MyBatis初始化過程中,大致有以下幾個步驟:分解所有IT類編制
創(chuàng)建Configuration全局配置對象時,TypeAliasRegistry別名注冊中心將添加Mybatis所需的相關類,并將基于語言的默認類設置為加載XMLLanguageDriver的myba配置文件、Mapper界面的詳圖索引信息和XML映射文件。解析的配置信息構成相應的對象,并存儲在Configuration全局配置對象中。構建DefaultSqlSessionFactory對象可以創(chuàng)建DefaultSqlSession對象。MyBatis的SqlSession的默認實現類在整個初始化過程中包含更多代碼。
由于在《MyBatis初始化(一)之加載myba》 《MyBatis初始化(二)之加載Mapper接口與XML映射文件》 《MyBatis初始化(三)之SQL初始化(上)》 《MyBatis初始化(四)之SQL初始化(下)》 MyBatis初始化期間解析Mapper接口與XML映射文件相關的篇幅很多,XML映射文件的解析過程也很復雜,因此分為以下三個模塊,逐步分析,易于理解。
初始化(b)加載映射接口和映射文件
上一個模塊分析了如何解析myba配置文件。最后,尚未分析解析Mapper/標簽的方法。這個過程比較復雜,因為需要解析映射程序接口和XML映射文件。讓我們看一下這個解析過程
解析XML映射文件生成的對象主要如下圖所示。
默認程序包路徑:org.a、org.a
主要涉及的類:
Org.a.XML.XMLConfigBuilder:解析配置文件,開始初始化Mapper接口和XML映射文件,創(chuàng)建Configuration全局配置對象org.a:Mapper接口注冊中心,Mapper這里我們解析的Mapper接口是org . a . apperorg.a.XML.XMLMapperBuilder:剖析XML映射文件org.a.xml.XMLStatementBuilder:剖析XML Delete/insert/標簽)org.a. mapperbuilderassistant也就是說,Java類型和JDBC類型之間的映射信息org.a.ResultMap: resultMap/標記的配置信息和存儲子標記的所有信息org.a.MappedStatement:解析select/upps
讓我們回顧一下前面的模塊。org.a.xml.XMLConfigBuilder解析myba配置文件中的mapper/標記,并調用parse()-parse configuration(xnode roon)
private void mapper element(xnode parent)throws exception {
If(零件!=空){
//0通過子節(jié)點
For (xnodechild3360 ()) {
//1如果是package標簽,請掃描包
If ('package ')。equal(){
//獲取軟件包名稱
字串mapper package=c(' name ');
//添加到配置
CON(MAPPERPACKAGE);
}如果是else {//mapper標簽
獲取//resource、URL和class屬性
string resource=c(' resource ');
字串URL=c(' URL ');
字串mapper class=c(' class ');
//2使用相對于類路徑的資源引用
If(資源!=null URL==null mapper class==null){
ErrorCon()。資源(資源);
從//resource導入InputStream對象
Inputstream inputstream=re(資源);
//創(chuàng)建XMLMapperBuilder對象
xmlmapperbuildermapperparser=new xmlmapperbuilder(input stream、configuration、resource、con());
//執(zhí)行解決
MA();
//3使用完全限定的資源定位器(URL)
} else if (resource==空URL!=空映射類==空){
ErrorCon()。資源(URL);
獲取//URL的InputStream對象
InputStream InputStream=Re(URL);
//創(chuàng)建XMLMapperBuilder對象
xmlmapperbuildermapperparser=new xmlmapperbuilder(input stream、configuration、URL、con());
//執(zhí)行解決
MA();
//4使用映射程序接口實現類的完全限定類名
} else if(resource==null URL==null mapper class!=空){
//Mapper接口導入
班級?mapper interface=Re(mapper class);
//添加到配置
地圖界面(con);
} else {
throw new builder exception(' a mapper element may only specify a URL,resource or class,but not more than one . '));
}
}
}
}
}
遍歷Mapper/標記的子節(jié)點
對于Package/子節(jié)點,導入解析包路徑下Mapper接口的Package屬性后,通過子節(jié)點的resource屬性或URL屬性解析映射文件,或通過class屬性解析Mapper接口,通常會直接配置包路徑,因此可以看到上面的第一對
首先,將軟件包軟件包路徑添加到Configuration全局配置對象中。也就是說,通過調用調用內部MapperRegistry注冊表和MapperRegistry的addMappers(字符串包名)方法進行注冊
讓我們看一下如何在MapperRegistry注冊表中解析。此類在上一文檔的Binding模塊中解釋如下:
Public class MapperRegistry {
public void add mappers(string package name){
Addmappers(軟件包名稱,object . class);
}
/* *
*用于在指定軟件包中搜索Mapper接口并將其綁定到XML文件
* @since 3.2.2
*/
public void add mappers(string package name,class?SuperType) {
//1搜索指定程序包下的指定類
ResolverUtilClass?ResolverUtil=new ResolverUtil();
Re (new re (supertype),package name);
SetClass?Extends Class?MapperSet=re();
//2巡回,添加到knownMappers
For(類?MapperClass : mapperSet) {
add mapper(mapper class);
}
}
public t void add mapper(class type){
//1判斷,必須是接口。
if ()) {
// <2> 已經添加過,則拋出 BindingException 異常
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
// <3> 將Mapper接口對應的代理工廠添加到 knownMappers 中
knownMa(type, new MapperProxyFactory<>(type));
// It's important that the type is added before the parser is run
// otherwise the binding may automatically be attempted by the mapper parser.
// If the type is already known, it won't try.
// <4> 解析 Mapper 的注解配置
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
// 解析 Mapper 接口上面的注解和 Mapper 接口對應的 XML 文件
();
// <5> 標記加載完成
loadCompleted = true;
} finally {
// <6> 若加載未完成,從 knownMappers 中移除
if (!loadCompleted) {
knownMa(type);
}
}
}
}
}
<1>首先必須是個接口
<2>已經在MapperRegistry注冊中心存在,則會拋出異常
<3>創(chuàng)建一個Mapper接口對應的MapperProxyFactory動態(tài)代理工廠
<4>【重要?。?!】通過MapperAnnotationBuilder解析該Mapper接口與對應XML映射文件
MapperAnnotationBuilder
org.a.annotation.MapperAnnotationBuilder:解析Mapper接口,主要是解析接口上面注解,加載XML文件會調用XMLMapperBuilder類進行解析
我們先來看看他的構造函數和parse()解析方法:
public class MapperAnnotationBuilder {
/**
* 全局配置對象
*/
private final Configuration configuration;
/**
* Mapper 構造器小助手
*/
private final MapperBuilderAssistant assistant;
/**
* Mapper 接口的 Class 對象
*/
private final Class<?> type;
public MapperAnnotationBuilder(Configuration configuration, Class<?> type) {
String resource = ().replace('.', '/') + ".java (best guess)";
= new MapperBuilderAssistant(configuration, resource);
= configuration;
= type;
}
public void parse() {
String resource = ();
if (!con(resource)) {
// 加載該接口對應的 XML 文件
loadXmlResource();
con(resource);
a(());
// 解析 Mapper 接口的 @CacheNamespace 注解,創(chuàng)建緩存
parseCache();
// 解析 Mapper 接口的 @CacheNamespaceRef 注解,引用其他命名空間
parseCacheRef();
Method[] methods = ();
for (Method method : methods) {
try {
// issue #237
if (!me()) { // 如果不是橋接方法
// 解析方法上面的注解
parseStatement(method);
}
} catch (IncompleteElementException e) {
con(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
private void loadXmlResource() {
// Spring may not know the real resource name so we check a flag
// to prevent loading again a resource twice
// this flag is set at XMLMapperBuilder#bindMapperForNamespace
if (!con("namespace:" + ())) {
String xmlResource = ().replace('.', '/') + ".xml";
// #1347
InputStream inputStream = ("/" + xmlResource);
if (inputStream == null) {
// Search XML mapper that is not in the module but in the classpath.
try {
inputStream = Re(), xmlResource);
} catch (IOException e2) {
// ignore, resource is not required
}
}
if (inputStream != null) {
// 創(chuàng)建 XMLMapperBuilder 對象
XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, a(),
xmlResource, con(), ());
// 解析該 XML 文件
xmlPar();
}
}
}
}
在構造函數中,會創(chuàng)建一個MapperBuilderAssistant對象,Mapper 構造器小助手,用于創(chuàng)建XML映射文件中對應相關對象
parse()方法,用于解析Mapper接口:
- 獲取Mapper接口的名稱,例如in,根據Configuration全局配置對象判斷該Mapper接口是否被解析過
- 沒有解析過則調用loadXmlResource()方法解析對應的XML映射文件
- 然后解析接口的@CacheNamespace和@CacheNamespaceRef注解,再依次解析方法上面的MyBatis相關注解
注解的相關解析這里就不講述了,因為我們通常都是使用XML映射文件,邏輯沒有特別復雜,都在MapperAnnotationBuilder中進行解析,感興趣的小伙伴可以看看
1.《如何初始化接口?終于找到答案了MyBatis初始化加載 Mapper 接口與XML文件》援引自互聯網,旨在傳遞更多網絡信息知識,僅代表作者本人觀點,與本網站無關,侵刪請聯系頁腳下方聯系方式。
2.《如何初始化接口?終于找到答案了MyBatis初始化加載 Mapper 接口與XML文件》僅供讀者參考,本網站未對該內容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉載時請保留本站內容來源地址,http://f99ss.com/gl/2093880.html