總結完這個Mybatis的整體主要功能基本上就差不多完,還有一些細節的部分,后續都會記錄補充。
插件這個東西一般用的比較少,就算用的多的插件也算是PageHelper分頁插件;
PageHelper官網:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md
官網上這個也有談到Mybatis的插件流程分析。
使用示例
插件類
記錄SQL執行的時間,
1、在JDK8之前必須實現Interceptor接口中的三個方法,在JDK8之后只需要實現intercept方法即可;
2、加上@Intercepts注解,并且附加上需攔截的類型以及方法@Signature:
? ? type:插入的類,即指定的四個類型;
? ? method:攔截插入類的方法;
? ? args:攔截插入類方法的參數類型,按順序。
3、實現的plugin方法,必須執行Plugin.wrap(target, this);JDK8之后在接口中寫了默認方法。
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class })
})
public class ThresHolderPlugin implements Interceptor {int threshold = 0;public Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();Object proceed = invocation.proceed();long end = System.currentTimeMillis();System.out.println("select time: " + (end-start) + "ms");return proceed;}public Object plugin(Object target) {return Plugin.wrap(target, this);}public void setProperties(Properties properties) {this.threshold = Integer.valueOf(properties.getProperty("value"));System.out.println("threshold :" + threshold);}}
?配置文件
<plugins><plugin interceptor="com.test.mybatis.MybatisTest.official.plugin.ThresHolderPlugin">//數據會傳輸到插件類的Properties<property name="value" value="10"></property></plugin></plugins>
設計模式
責任鏈模式(Chain of Responsibility Pattern)
為請求創建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發送者和接收者進行解耦。這種類型的設計模式屬于行為型模式。
在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推。
責任鏈模式優點:
降低耦合度。它將請求的發送者和接收者解耦。
簡化了對象。使得對象不需要知道鏈的結構。
增強給對象指派職責的靈活性。通過改變鏈內 的成員或者調動它們的次序,允許動態地新增 或者刪除責任。
增加新的請求處理類很方便。
UML:
Handler:定義了一個處理請求的標準接口;
ConcreteHandler:具體的處理者,處理它負 責的部分,根據業務可以結束處理流程,也可 以將請求轉發給它的后繼者;
client :發送者,發起請求的客戶端;
源碼分析
在之前談到Mybatis的核心流程分析中在加載Mybatis的配置文件的時候會把所有的插件加載帶Configuration對象中的InterceptorChain變量當中,
如果有多個插件類的話,因為InterceptorChain類儲存插件類是有序集合,所以執行插件的順序就是在xml配置插件的順序;
在Configuration類中:
這里有個CacheExecutor執行器,當開啟了二級緩存的時候,就是選用緩存執行器,使用是裝飾器模式將真正的執行器包裝了一層。
我們現在看一下這個pluginAll方法:
使用動態代理將真正的對象進行增強;
在之前那個方法中,必須執行Invocation的proceed()方法,這個方法就是執行method.invoke()方法;
如果有多個插件的話,那么就會出現重復代理對象,那么重復代理對象的執行的話,執行過程如下:
這就是責任鏈模式,一層嵌套著一層。
在配置XML文件中配置:
<plugins><plugin interceptor="com.test.mybatis.MybatisTest.official.plugin.ThresHolderPlugin"><property name="value" value="10"></property></plugin><plugin interceptor="com.test.mybatis.MybatisTest.official.plugin.ThresHolderPlugin2"><property name="value" value="20"></property></plugin>
</plugins>
那么執行的過程就是:
ThresHolderPlugin2{
? ? ?ThresHolderPlugin{
? ? ? ? ? ?interceptor.intercept(new Invocation(target, method, args))
? ? ?}
}
?插件的執行流程差不多了。大家可以在評論區多交流交流。