摘要:插件插件接口在中使用插件,我們必須實(shí)現(xiàn)接口。它將直接覆蓋你所攔截對(duì)象原有的方法,因此它是插件的核心方法。插件在對(duì)象中的保存插件的代理和反射設(shè)計(jì)插件用的是責(zé)任鏈模式,的責(zé)任鏈?zhǔn)怯扇ザx的。
插件 1、插件接口
在MyBatis中使用插件,我們必須實(shí)現(xiàn)接口Interceptor。
public interface Interceptor { // 它將直接覆蓋你所攔截對(duì)象原有的方法,因此它是插件的核心方法。 // Intercept里面有個(gè)參數(shù)Invocation對(duì)象,通過它可以反射調(diào)度原來對(duì)象的方法 Object intercept(Invocation invocation) throws Throwable; // 作用是給被攔截對(duì)象生成一個(gè)代理對(duì)象,并返回它。target是被攔截對(duì)象 Object plugin(Object target); // 允許在plugin元素中配置所需參數(shù),方法在插件初始化的時(shí)候就被調(diào)用了一次 void setProperties(Properties properties); }2、插件初始化
插件的初始化是在MyBatis初始化的時(shí)候完成的。
public class XMLConfigBuilder extends BaseBuilder { ...... private void pluginElement(XNode parent) throws Exception { if (parent != null) { for (XNode child : parent.getChildren()) { String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance(); interceptorInstance.setProperties(properties); configuration.addInterceptor(interceptorInstance); } } } }
在解析配置文件的時(shí)候,在MyBatis的上下文初始化過程中,就開始讀入插件節(jié)點(diǎn)和我們配置的參數(shù),同時(shí)使用反射技術(shù)生成對(duì)應(yīng)的插件實(shí)例,然后調(diào)用插件方法中的setProperties方法,設(shè)置我們配置的參數(shù),然后將插件實(shí)例保存到配置對(duì)象中,以便讀取和使用它。
插件在Configuration對(duì)象中的保存:
public void addInterceptor(Interceptor interceptor) { interceptorChain.addInterceptor(interceptor); }3、插件的代理和反射設(shè)計(jì)
插件用的是責(zé)任鏈模式,MyBatis的責(zé)任鏈?zhǔn)怯蒳nterceptorChain去定義的。在MyBatis創(chuàng)建Executor執(zhí)行器的時(shí)候,我們可以看到有如下的一段代碼:
executor = (Executor) interceptorChain.pluginAll(executor);
再看下Interceptor的pluginAll方法:
public class InterceptorChain { private final Listinterceptors = new ArrayList (); public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { // plugin方法是生成代理對(duì)象的方法 // 可以看出來,如果有多個(gè)插件的話,會(huì)生成多層代理的代理對(duì)象 target = interceptor.plugin(target); } return target; } ...... }
MyBatis為我們提供了Plugin類用于生成代理對(duì)象。
public class Plugin implements InvocationHandler { ...... public static Object wrap(Object target, Interceptor interceptor) { Map, Set > signatureMap = getSignatureMap(interceptor); Class> type = target.getClass(); Class>[] interfaces = getAllInterfaces(type, signatureMap); if (interfaces.length > 0) { return Proxy.newProxyInstance( type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)); } return target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Set methods = signatureMap.get(method.getDeclaringClass()); // 如果存在簽名的攔截方法,插件的intercept方法將被調(diào)用 if (methods != null && methods.contains(method)) { return interceptor.intercept(new Invocation(target, method, args)); } // 否則,直接反射調(diào)度我們要執(zhí)行的方法 return method.invoke(target, args); } catch (Exception e) { throw ExceptionUtil.unwrapThrowable(e); } } }
在調(diào)用插件的攔截方法時(shí),可以看到傳遞了一個(gè)新創(chuàng)建的Invocation對(duì)象。
interceptor.intercept(new Invocation(target, method, args));
Invocation類封裝了被代理的對(duì)象、方法及其參數(shù)。
public class Invocation { public Invocation(Object target, Method method, Object[] args) { this.target = target; this.method = method; this.args = args; } // 這個(gè)方法會(huì)調(diào)度被代理對(duì)象的真實(shí)方法, 所以我們通過這個(gè)方法直接調(diào)用被代理對(duì)象原來的方法 // 如果多個(gè)插件的話,我們知道會(huì)生成多層代理對(duì)象,那么每層被代理都可以通過Invocation調(diào)用這個(gè)proceed方法, // 所以在多個(gè)插件的環(huán)境下,調(diào)度proceed()方法時(shí),MyBatis總是從最后一個(gè)代理對(duì)象運(yùn)行到第一個(gè)代理對(duì)象, // 最后是真實(shí)被攔截的對(duì)象方法被運(yùn)行 public Object proceed() throws InvocationTargetException, IllegalAccessException { return method.invoke(target, args); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69549.html
摘要:的解析和運(yùn)行原理構(gòu)建過程提供創(chuàng)建的核心接口。在構(gòu)造器初始化時(shí)會(huì)根據(jù)和的方法解析為命令。數(shù)據(jù)庫(kù)會(huì)話器定義了一個(gè)對(duì)象的適配器,它是一個(gè)接口對(duì)象,構(gòu)造器根據(jù)配置來適配對(duì)應(yīng)的對(duì)象。它的作用是給實(shí)現(xiàn)類對(duì)象的使用提供一個(gè)統(tǒng)一簡(jiǎn)易的使用適配器。 MyBatis的解析和運(yùn)行原理 構(gòu)建SqlSessionFactory過程 SqlSessionFactory提供創(chuàng)建MyBatis的核心接口SqlSess...
摘要:學(xué)習(xí)筆記有官方的中文開發(fā)文檔并且針對(duì)使用者比較友好是一款優(yōu)秀的持久層框架,它支持定制化存儲(chǔ)過程以及高級(jí)映射。它只和配置有關(guān),存在的意義僅在于用來減少類完全限定名的冗余,為了簡(jiǎn)化中的書寫。 Mybatis學(xué)習(xí)筆記 mybatis有官方的中文開發(fā)文檔并且針對(duì)使用者比較友好:http://www.mybatis.org/mybatis-3/zh/ MyBatis 是一款優(yōu)秀的持久層框架,它支...
摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進(jìn)階面試問題列表 -...
摘要:插件功能非常強(qiáng)大,,方法跳轉(zhuǎn)提示,分頁插件。三地址使用該插件在引入該插件具體使用,我們?cè)谝院蟮闹性賹W(xué)習(xí)具體的方法。更多請(qǐng)參考學(xué)習(xí)筆記一入門 mybatis 插件功能非常強(qiáng)大,mybatis-generator,mybatis-plugin方法跳轉(zhuǎn)提示,mybatis-pagehelper分頁插件。 一、mybatis-generator 1、mybatis-generator配置 先在...
閱讀 1964·2021-09-07 09:59
閱讀 2528·2019-08-29 16:33
閱讀 3701·2019-08-29 16:18
閱讀 2860·2019-08-29 15:30
閱讀 1687·2019-08-29 13:52
閱讀 2050·2019-08-26 18:36
閱讀 544·2019-08-26 12:19
閱讀 707·2019-08-23 15:23