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...