日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

犯罪心理解读Mybatis拦截器

發布時間:2025/5/22 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 犯罪心理解读Mybatis拦截器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文鏈接:"犯罪心理"解讀Mybatis攔截器

Mybatis攔截器執行過程解析 文章寫過之后,我覺得 “Mybatis 攔截器案件”背后一定還隱藏著某種設計動機,里面大量的使用了 Java 動態代理手段,它是怎樣應用這個手段優雅的設計出整個攔截事件的?就像抓到罪犯要了解它犯罪動機是什么一樣,我們需要解讀 Mybatis攔截器的設計理念:

設計解讀

Java 動態代理我們都懂得,我們先用它設計一個基本攔截器
首先定義目標對象接口:

public interface Target {public void execute(); }

然后,定義實現類實現其接口:

public class TargetImpl implements Target {public void execute() {System.out.println("Execute");} }

最后,使用 JDK 動態代理定義一個代理類,用于為目標類生成代理對象:

public class TargetProxy implements InvocationHandler {private Object target;private TargetProxy(Object target) {this.target = target;}//代理對象生成目標對象public static Object bind(Object target) {return Proxy.newProxyInstance(target.getClass() .getClassLoader(), target.getClass().getInterfaces(),new TargetProxy(target));}//public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {System.out.println("Begin");return method.invoke(target, args);} }

這時,客戶端調用方式如下:

public class Client {public static void main(String[] args) {//沒被代理之前Target target = new TargetImpl();target.execute(); //執行結果://Execute//被代理之后target = (Target)TargetProxy.bind(target);target.execute(); //執行結果://Begin//Execute} }

應用上面的設計方式,攔截邏輯是寫死在代理類中的:

public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {//攔截邏輯在代理對象中寫死了,這樣到這客戶端沒有靈活的設置來攔截其邏輯System.out.println("Begin");return method.invoke(target, args); }

這樣的設計方式不夠靈活和高可用,可能滿足 ClientA 的攔截需求,但是不能滿足 ClientB 的攔截需求,這不是一個好的攔截方案,所以我們需要進一步更改設計方案:
將攔截邏輯封裝成一個類,客戶端綁定在調用TargetProxy()方法時將攔截邏輯一起作為參數,這樣客戶端可以靈活定義自己的攔截邏輯,為實現此功能,我們需要定一個攔截器接口 Interceptor

public interface Interceptor {public void intercept(); }

將代理類做一個小改動,在客戶端實例化 TargetProxy 的時候可以傳入自定義的攔截器:

public class TargetProxy implements InvocationHandler {private Object target;//攔截器private Interceptor interceptor;private TargetProxy(Object target, Interceptor interceptor) {this.target = target;this.interceptor = interceptor;}//通過傳入客戶端封裝好 interceptor 的方式為 target 生成代理對象,使得客戶端可以靈活使用不同的攔截器邏輯public static Object bind(Object target, Interceptor interceptor) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new TargetProxy(target, interceptor));}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//客戶端實現自定義的攔截邏輯interceptor.intercept();return method.invoke(target, args);} }

通過這樣,就解決了“攔截內容固定死”的問題了,再來看客戶端的調用方式:

//客戶端可以在此處定義多種攔截邏輯 Interceptor interceptor = new Interceptor() {public void intercept() {System.out.println("Go Go Go!!!");} }; target = (Target)TargetProxy.bind(target, interceptor); target.execute();

上面的 interceptor() 是個無參方法,難道犯罪分子冒著生命危險攔截目標只為聽目標說一句話 System.out.println(“Go Go Go!!!”)? 很顯然它需要了解目標行為(Method)和注意目標的身外之物(方法參數),繼續設置"圈套",將攔截接口做個改善:

public interface Interceptor {public void intercept(Method method, Object[] args); }

同樣需要改變代理類中攔截器的調用方式,將 method 和 args 作為參數傳遞進去

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//攔截器拿到method和args信息可以做更多事情,而不只是打招呼了interceptor.intercept(method, args);return method.invoke(target, args); }

進行到這里,方案看似已經不錯了,靜待客戶上鉤,但這違背了做一名有追求罪犯的基本原則:「迪米特法則」

迪米特法則(Law of Demeter)又叫作最少知識原則(Least Knowledge Principle 簡寫LKP),就是說一個對象應當對其他對象有盡可能少的了解, 不和陌生人說話。英文簡寫為: LoD,是一種解耦的方式.

上面代碼中,method 需要知道 target 和 args;interceptor 需要知道 method 和 args,這樣就可以在 interceptor 中調用 method.invoke,但是攔截器中并沒有 invoke 方法需要的關鍵參數 target,所以我們將 target,method,args再進行一次封裝成 Invocation類,這樣攔截器只需要關注 Invocation 即可.

public class Invocation {private Object target;private Method method;private Object[] args;public Invocation(Object target, Method method, Object[] args) {this.target = target;this.method = method;this.args = args;}//成員變量盡可能在自己的內部操作,而不是 Intereptor 獲取自己的成員變量來操作他們public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}public Method getMethod() {return method;}public void setMethod(Method method) {this.method = method;}public Object[] getArgs() {return args;}public void setArgs(Object[] args) {this.args = args;} }

這樣攔截器接口變了樣子:

public interface Interceptor {public Object intercept(Invocation invocation)throws Throwable ; }

代理類也隨之做了改變:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return interceptor.intercept(new Invocation(target, method, args)); }

這樣客戶端調用,在攔截器中,攔截器寫了自己攔截邏輯之后,執行 invocation.proceed() 即可觸發原本 target 的方法執行:

Interceptor interceptor = new Interceptor() {public Object intercept(Invocation invocation) throws Throwable {System.out.println("Go Go Go!!!");return invocation.proceed();} };

到這里,我們經過一系列的調整和設計,結果已經很好了,但仔細想,這種攔截方式會攔截 target 的所有方法,假如 Target 接口有多個方法:

public interface Target {/*** 去銀行存款*/public void execute1();/*** 倒垃圾*/public void execute2(); }

以上兩個方法,當然是攔截 target 去銀行存款才是利益價值最大化的攔截,攔截 target 去倒垃圾有什么用呢?(避免沒必要的攔截開銷),所以我們標記攔截器只有在發生去銀行存款的行為時才采取行動,先自定義一個注解用來標記攔截器

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MethodName {public String value(); }

在攔截器實現類上添加該標識:

//去銀行存款時攔截 @MethodName("execute1") public class InterceptorImpl implements Interceptor {... }

修改代理類,如果注解標記的方法是否與 method 的方法一致,則執行攔截器:

public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {MethodName methodName = this.interceptor.getClass().getAnnotation(MethodName.class);if (ObjectUtils.isNull(methodName)){throw new NullPointerException("xxxx");}//如果方法名稱和注解標記的方法名稱相同,則攔截String name = methodName.value();if (name.equals(method.getName())){return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(this.target, args); }

到這里,戶端的調用變成了這個樣子:

Target target = new TargetImpl(); Interceptor interceptor = new InterceptorImpl(); target = (Target)TargetProxy.bind(target, interceptor); target.execute();

從上面可以看出,客戶端第一步創建 target 對象和 interceptor 對象,通過傳入 target 和 interceptor 調用 bind 方法生成代理對象,最終代理對象調用 execute 方法,根據迪米特法則,客戶端不需要了解 TargetProxy,只需要關注攔截器的內部邏輯和可調用的方法即可,所以我們需要繼續修改設計方案,添加 register(Object object)方法,:

public interface Interceptor {public Object intercept(Invocation invocation) throws Throwable ;public Object register(Object target); }

修改攔截器的實現,攔截器對象通過調用 register 方法為 target 生成代理對象:

@MethodName("execute1") public class InterceptorImpl implements Interceptor {public Object intercept(Invocation invocation)throws Throwable {System.out.println("Go Go Go!!!");return invocation.proceed();}public Object register(Object target) {return TargetProxy.bind(target, this);} }

現在,客戶端調用變成了這個樣子:

Target target = new TargetImpl(); Interceptor interceptor = new InterceptorImpl();target = (Target)interceptor.register(target); target.execute1();

客戶端只需要實例化攔截器對象,并調用攔截器相應的方法即可,非常清晰明朗
一系列的設計改變,恰巧符合 Mybatis攔截器的設計思想,我們只不過用一個非常簡單的方式去理解它
Mybatis 將自定義的攔截器配置添加到 XML 文件中,或者通過注解的方式添加到上下文中,以 XML 形式舉例:

<plugins><plugin interceptor="com.gs.cvoud.dao.interceptor.MapInterceptor" /></plugins>

通過讀取配置文件,將所有攔截器都添加到 InterceptorChain 中

public class InterceptorChain {private final List<Interceptor> interceptors = new ArrayList<Interceptor>();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {// 該方法和我們上面自定義攔截器中 register 方法功能一致target = interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public List<Interceptor> getInterceptors() {return Collections.unmodifiableList(interceptors);}}

但 Mybatis 框架邏輯限制,只能為:ParameterHandler,ResultSetHandler,StatementHandler 和 Executor 創建代理對象
我們在此將我們的簡單實現與 Mybatis 實現的核心內容做個對比:
生成代理對象:

攔截指定方法,如果找不到方法,拋出異常:

執行目標方法:

到這里,沒錯,犯罪現場完美推測出,真相就是這樣!!!
墻裂建議先看 Mybatis攔截器執行過程解析 ,然后回看該文章,了解 Mybatis 攔截器的整個設計動機與理念,大道至簡.

靈魂追問

  • 除了迪米特設計原則,你還知道哪些設計基本原則?
  • 你在編寫代碼時,考慮過怎樣利用那些設計原則來規范自己代碼嗎?
  • ...
  • 推薦閱讀

  • 不得不知的責任鏈設計模式
  • Mybatis攔截器執行過程解析
  • 如何使用Mybatis的攔截器實現數據加密與解密
  • 如何設計好的RESTful API
  • 輕松高效玩轉DTO(Data Transfer Object)

  • 那些可以提高效率的工具

    關注公眾號了解更多可以提高工作效率的工具,同時帶你像看偵探小說一樣趣味學習 Java 技術


    轉載于:https://www.cnblogs.com/FraserYu/p/11095078.html

    總結

    以上是生活随笔為你收集整理的犯罪心理解读Mybatis拦截器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 成人一二三四区 | 精品人妻一区二区三区免费 | 日本黄色大片网站 | 一级特黄bbbbb免费观看 | 老外毛片| 91蜜桃婷婷狠狠久久综合9色 | 精品免费久久久 | 爱爱视频天天干 | 亚洲欧洲日韩av | av网天堂 | 亚洲生活片 | 麻豆久久久午夜一区二区 | 色丁香婷婷综合久久 | 少妇做爰k8经典 | 成熟了的熟妇毛茸茸 | 欧美黑人一级爽快片淫片高清 | 亚色图 | 五月婷网站 | 日日躁夜夜躁狠狠久久av | 日本xxxx在线观看 | www.亚洲免费 | 关秀媚三级 | 国产黑丝一区二区 | 国产99久久久国产精品成人免费 | 日韩欧美一区二区一幕 | 欧美日韩不卡一区二区 | 国产精品久久影视 | 成人激情综合网 | 中国女人内谢69xxxx免费视频 | 波多野结衣调教 | 97麻豆| 久久伊人超碰 | 性视频久久 | 日韩在线不卡视频 | 色狠狠一区二区三区香蕉 | 亚洲香蕉av| www.97色| 亚洲天堂第一 | 国产精品美乳在线观看 | 午夜欧美精品 | 成人性生生活性生交全黄 | 成人小视频免费观看 | 黄色网络在线观看 | 毛片毛片毛片毛片毛片毛片毛片 | 国产综合在线视频 | chinese精品自拍hd | 欧美激情成人 | 欧美888 | 伊人av网站 | 国产二区三区视频 | 国产成人无码av在线播放dvd | 夜色视频在线观看 | 日韩黄色大片 | 伊人久久影院 | 中文字幕黑人 | 国产欧美一区二区三区视频 | 亚州视频在线 | 成人日皮视频 | 日本一区二区三区四区五区 | 亚洲精品一二区 | 国产精品久久av无码一区二区 | 国产精品99精品无码视亚 | 91大神在线观看视频 | 午夜激情国产 | 久久97人妻无码一区二区三区 | 亚洲一区无 | 亚洲欧美精品在线 | 毛片看看 | 欧美一卡二卡三卡四卡 | 国产日韩欧美在线观看视频 | 久久久久久久极品 | 国产吃瓜黑料一区二区 | 爱爱免费网站 | 青青草原免费观看 | 日韩欧美在线播放 | 久久久久九九九九 | 国产寡妇亲子伦一区二区三区四区 | 凹凸福利视频 | 天天激情 | 色网站观看 | 精品中文字幕一区二区三区 | 中日韩午夜理伦电影免费 | 好男人www日本 | 中文精品一区二区三区 | 91福利视频在线观看 | 91无限观看 | 在线天堂资源 | 亚洲色图.com | 日韩精品第一区 | www.色国产 | 日本老熟妇毛茸茸 | 中文在线免费 | 少妇熟女一区二区三区 | www.白丝 | 玖玖爱在线观看 | 日韩美女毛片 | 韩日黄色 | 亚洲人成网址 | 超碰一区 |