深入淺出Mybatis 外掛程式原理

2021-06-15 07:26:13 字數 4156 閱讀 2477

mybatis採用責任鏈模式,通過動態**組織多個***(外掛程式),通過這些***可以改變mybatis的預設行為(諸如sql重寫之類的),由於外掛程式會深入到mybatis的核心,因此在編寫自己的外掛程式前最好了解下它的原理,以便寫出安全高效的外掛程式。

mybatis

支援對executor

、statementhandler

、pameterhandler

和resultsethandler

進行攔截,也就是說會對這

4種物件進行**。下面以

executor

為例。mybatis

在建立executor

物件時會執行下面一行**:

executor =(executor) interceptorchain.pluginall(executor);

interceptorchain

裡儲存了所有的***,它在

mybatis

初始化的時候建立。上面這句**的含義是呼叫***鏈裡的每個***依次對

executor

進行plugin

(插入?)**如下:

/**

* 每乙個***對目標類都進行一次**

* @paramtarget

* @return 層層**後的物件

*/public objectpluginall(object target)

returntarget;

}

下面以乙個簡單的例子來看看這個

plugin

方法裡到底發生了什麼。

public class exampleplugin implements interceptor

@override

public objectplugin(object target)

@override

public voidsetproperties(properties properties)

}每乙個***都必須實現上面的三個方法,其中:

1)       

object intercept(invocation invocation)

是實現攔截邏輯的地方,內部要通過

invocation.proceed()

顯式地推進責任鏈前進,也就是呼叫下乙個***攔截目標方法。

2)       

object plugin(object target)

就是用當前這個***生成對目標

target

的**,實際是通過

plugin.wrap(target,this)

來完成的,把目標

target

和***

this

傳給了包裝函式。

3)       

setproperties(properties properties)

用於設定額外的引數,引數配置在***的

properties

節點裡。

註解裡描述的是指定攔截方法的簽名

[type,method,args] (即對哪種物件的哪種方法進行攔截),它在攔截前用於決斷。

從前面可以看出,每個***的

plugin

方法是通過呼叫

plugin.wrap

方法來實現的。**如下:

public staticobject wrap(object target, interceptor interceptor) 

returntarget;

}

這個plugin

類有三個屬性:

private object target;//被**的目標類

private interceptor interceptor;//對應的***

private map, set> signaturemap;//***攔截的方法快取

我們再次結合

(executor)interceptorchain.pluginall(executor)

這個語句來看,這個語句內部對

executor

執行了多次

plugin,

第一次plugin

後通過plugin.wrap

方法生成了第乙個**類,姑且就叫

executorproxy1

,這個**類的

target

屬性是該

executor

物件。第二次

plugin

後通過plugin.wrap

方法生成了第二個**類,姑且叫

executorproxy2

,這個**類的

target

屬性是executorproxy1...

這樣通過每個**類的

target

屬性就構成了乙個**鏈(從最後乙個

executorproxyn

往前查詢,通過

target

屬性可以找到最原始的

executor

類)。

**鏈生成後,對原始目標的方法呼叫都轉移到**者的invoke

方法上來了。

plugin

作為invocationhandler

的實現類,他的

invoke

方法是怎麼樣的呢?

public objectinvoke(object proxy, method method, object args) throws throwable 

returnmethod.invoke(target, args);

} catch(exception e)

}

invoke

裡,如果方法簽名和攔截中的簽名一致,就呼叫***的攔截方法。我們看到傳遞給***的是乙個

invocation

物件,這個物件是什麼樣子的,他的功能又是什麼呢?

public class invocation 

...public objectproceed() throws invocationtargetexception, illegalacces***ception

}

可以看到,

invocation

類儲存了**物件的目標類,執行的目標類方法以及傳遞給它的引數。

在每個***的

intercept

方法內,最後乙個語句一定是

returninvocation.proceed()

(不這麼做的話***鏈就斷了,你的

mybatis

基本上就不能正常工作了)。

invocation.proceed()

只是簡單的呼叫了下

target

的對應方法,如果

target

還是個**,就又回到了上面的

plugin.invoke

方法了。這樣就形成了***的呼叫鏈推進。

public object intercept(invocation invocation) throws throwable
我們假設在

mybatis

配置了乙個外掛程式,在執行時會發生什麼?

1)       

所有可能被攔截的處理類都會生成乙個**

2)       

處理類**在執行對應方法時,判斷要不要執行外掛程式中的攔截方法

3)       

執行插接中的攔截方法後,推進目標的執行

如果有n個外掛程式,就有

n個**,每個**都要執行上面的邏輯。這裡面的層層**要多次生成動態**,是比較影響效能的。雖然能指定外掛程式攔截的位置,但這個是在執行方法時動態判斷,初始化的時候就是簡單的把外掛程式包裝到了所有可以攔截的地方。

因此,在編寫外掛程式時需注意以下幾個原則:

1)       

不編寫不必要的外掛程式;

2)       

實現plugin

方法時判斷一下目標型別,是本外掛程式要攔截的物件才執行

plugin.wrap

方法,否者直接返回目標本省,這樣可以減少目標被**的次數。

深入淺出MyBatis筆記 外掛程式

在mybatis中使用外掛程式,我們必須實現介面interceptor。public inte ce interceptor外掛程式的初始化是在mybatis初始化的時候完成的。public class xmlconfigbuilder extends basebuilder 在解析配置檔案的時候,...

深入淺出通訊原理筆記

論壇上的帖子 深入淺出通訊原理是比較不錯的技術貼,位址 摘錄一下比較有收穫的幾個部分 1 作者證明,卷積其實代表的就是求兩個多項式相乘之後的係數,如果能把訊號表示成多項式的形式,那麼訊號的相乘其實就可以表示成多項式的係數卷積。那能不能呢?答案是肯定的。而且如果x n最好和n w0有關,那這樣表示式就...

深入淺出sizeof

int佔 位元組,short佔 位元組 1.0 回答下列問題 答案在文章末尾 1.sizeof char 2.sizeof a 3.sizeof a 4.strlen a 如果你答對了全部四道題,那麼你可以不用細看下面關於sizeof的論述。如果你答錯了部分題目,那麼就跟著我來一起 關於sizeof...