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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

深度解析JAVA动态代理设计模式

發布時間:2025/6/15 asp.net 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度解析JAVA动态代理设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基本概念:Proxy模式也叫代理模式,所謂代理,是指具有與代理元(被代理的對象)具有相同的接口的類,客戶端必須通過代理與被代理的目標類交互,而代理一般在交互的過程中(交互前后),進行某些特別的處理(比如說,日志記錄,事務控制,權限過濾等等)。

(一)靜態代理

項目開發中,我們往往要在某些業務方法之前或者之后加上一些日志記錄,但是為了使業務方法更加專注于業務流程的實現,我們希望夠把這些記錄日志的語句從業務方法中脫離出來,使得整個程序的結構更加清晰。那么有什么方案能夠實現這個設計思路呢

下面我們寫個例子看看使用靜態代理的解決方案

首先我們設計一個IHello接口:

[java]?view plaincopyprint?
  • public?interface?IHello{??
  • ?????//假設這是一個業務方法??
  • ???public?void?sayHello(String?name);??
  • }??

  • 然后我們寫個類去實現上面這個接口:

    [java]?view plaincopyprint?
  • public?class?Hello?implements?IHello{??
  • ?????????public?void?sayHello(String?name){??
  • ??????????System.out.println("你好,"+name);??
  • ?????????}??
  • }??

  • 現在我們設計一個代理類為sayHello這個方法加上日志記錄:

    [java]?view plaincopyprint?
  • public?class?ProxyHello?implements?IHello{??
  • ????private?IHello?hello;??
  • ????public?ProxyHello(IHello?hello){??
  • ?????????this.hello=hello;??
  • ????}??
  • ????public?void?sayHello(String?name){??
  • ?????????System.out.println("sayHello?start......");??
  • ?????????hello.sayHello(name);??
  • ?????????System.out.println("sayHello?end......");??
  • ???}??
  • }??

  • 最后我們寫一個測試類:

    [java]?view plaincopyprint?
  • public?class?Test{??
  • ?????public?static?void?main(String[]?args){??
  • ??????????IHello?hello=new?ProxyHello(new?Hello());??
  • ??????????hello.sayHello("極度暴走");??
  • ?????}??
  • }??
  • 運行結果:

    sayHello start.....

    你好,極度暴走

    sayHello end ......

    從上面的代碼我們可以看出,hello對象(代理實例)是由ProxyHello這個代理所創建,無需修改Hello類中的sayHello方法便可為其添加日志記錄,并且,當我們以后不需要日志記錄時我們只要把生成hello對象的代碼改成如下便可:

    [java]?view plaincopyprint?
  • public?class?Test{??
  • ?????public?static?void?main(String[]?args){??
  • ??????????IHello?hello=new?Hello();??
  • ??????????hello.sayHello("極度暴走");??
  • ?????}??
  • }??
  • (二)動態代理

    設想一下,如果我們要為項目的所有類的方法加上日志記錄,那么根據靜態代理的解決方案,我們需要為所有的類設計各自的代理類,這樣顯然是很麻煩的,并且會使整個程序代碼的冗余度很高。這時我們就想,能不能有那么一個類專門用來為我們動態生成代理類,OK,動態代理就因此應運而生了

    先來看下動態代理類的設計:

    [java]?view plaincopyprint?
  • import?java.lang.reflect.InvocationHandler;??
  • import?java.lang.reflect.Method;??
  • import?java.lang.reflect.Proxy;??
  • ??
  • public?class?DynaProxy?implements?InvocationHandler{??
  • ????//委托對象,即要被代理的對象??
  • ????private?Object?delegate;??
  • ????//生成指定委托類的代理實例??
  • ????public??Object?bind(Object?delegate){??
  • ????????this.delegate=delegate;??
  • ????????return?Proxy.newProxyInstance(this.delegate.getClass().getClassLoader(),?this.delegate.getClass().getInterfaces(),?this);??
  • ????}??
  • ????//實現InvocationHandler的invoke方法,每個代理實例的方法會通過此方法調用委托對象的業務方法,同時加上我們需要的一些操作(如:日志記錄)??
  • ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args){??
  • ????????Object?result=null;???????
  • ????????try?{??
  • ????????????System.out.println("mehtod?start......");??
  • ????????????//反射調用委托對象,即被代理對象的業務方法??
  • ????????????result=method.invoke(delegate,?args);??
  • ????????????System.out.println("mehtod?end......");??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????return?result;??
  • ????}??
  • }??

  • 接下來我們設計一個測試類,從測試類中我們便可以看出動態代理的優勢:

    [java]?view plaincopyprint?
  • public?void?Test{??
  • ????public?static?void?main(){??
  • ????????IHello?hello=new?DynaProxy().bind(new?Hello());??
  • ????????hello.sayHello("極度暴走");??
  • ????????//這里假設我們還有IGoogbye接口和Googbye類??
  • ????????IGoogbye?googbye=new?DynaProxy.bind(new?Goodbye());??
  • ????????googbye.sayGoogbye("極度暴走");??
  • ????}??
  • }??
  • 運行結果:

    method? start.....

    你好,極度暴走

    method? end ......

    method? start.....

    再見,極度暴走

    method? end ......

    看出優勢了沒?

    簡而言之,動態代理為我們動態創建了委托類的代理實例,所有的類都可以通過DynaProxy這個代理類去生產代理實例,而不用為了每個類寫一個各自的代理類。

    那么動態代理是如何幫我們創建代理實例的呢?

    要解答這個問題,必須搞清楚以下幾點:

    ?

    1? Proxy.newProxyInstance接口

    InvocationHandler接口并沒有想象中的那么高深莫測,事實上,這個接口只定義了一個invoke方法,我們要求代理類去實現這個接口,也就是要求代理類要去實現這個invoke方法。上面的例子,我們在invoke這個方法中實現了在業務方法(method參數)前后加上了日志記錄操作。很顯然,我們最后想達到的效果是,當委托類(如Hello類)的某個方法被調用時,我們能夠將這個方法對象(Method)傳遞給我們的invoke方法,然后通過調用invoke方法實現我們需要的代理操作。

    那么invoke方法是什么時候被調用的呢?讓我們看完下面的內容再來思考這個問題。

    ?

    2 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法

    這個方法實現了代理實例的創建,通過查看JDK的源代碼,我發現這個方法的實現主要分下面幾個步驟

    步驟一:生成一個代理實例的類對象

    Class proxyClass = getProxyClass(loader, interfaces);

    步驟二:獲取proxyClass 對象中含有InvocationHandler.class參數的構造函數

    Constructor cons =proxyClass? .getConstructor(InvocationHandler.class);

    步驟三:調用上面的構造函數,將我們設計的InvocationHandler的實現類傳遞進去

    return (Object) cons.newInstance(new Object[] { handler });

    我們來分析一下第一步生成的類對象,這里我貼出生成的代理類的源代碼(反編譯得來的):

    [java]?view plaincopyprint?
  • import?java.lang.reflect.InvocationHandler;???
  • import?java.lang.reflect.Method;???
  • import?java.lang.reflect.Proxy;???
  • import?java.lang.reflect.UndeclaredThrowableException;???
  • ??
  • public?final?class?$Proxy0?extends?Proxy???
  • ??implements?IHello{???
  • ??private?static?Method?m0;???
  • ??private?static?Method?m1;???
  • ??private?static?Method?m2;???
  • ??private?static?Method?m3;???
  • ??static???
  • ??{??//創建我們傳遞進來的接口中的方法對象??
  • ??????m3?=?Class.forName("com.IHello").getMethod("sayHello",?new?Class[0]);???
  • ??????//下面三個方法對象是一個類對象應具有的幾個基礎方法??
  • ??????m0?=?Class.forName("java.lang.Object").getMethod("hashCode",?new?Class[0]);???
  • ??????m1?=?Class.forName("java.lang.Object").getMethod("equals",?new?Class[]?{?Class.forName("java.lang.Object")?});???
  • ??????m2?=?Class.forName("java.lang.Object").getMethod("toString",?new?Class[0]);???
  • ??????return;???
  • ??}???
  • ????
  • ??//帶有InvocationHandler參數的構造函數??
  • ??//查看父類Proxy的源代碼可以看出,Proxy類中擁有一個InvocationHandler類型的成員變量h??
  • ??public?$Proxy0(InvocationHandler?paramInvocationHandler){???
  • ????super(paramInvocationHandler);???
  • ??}???
  • ??
  • ??//調用invoke方法實現代理業務??
  • ??public?final?void?sayHello(){??????
  • ??????this.h.invoke(this,?m3,?null);???
  • ??????return;???
  • ??}???
  • ??
  • ??public?final?boolean?equals(Object?paramObject){??
  • ??????return?((Boolean)this.h.invoke(this,?m1,?new?Object[]?{?paramObject?})).booleanValue();???
  • ??}???
  • ??
  • ??public?final?int?hashCode()???{?????
  • ??????return?((Integer)this.h.invoke(this,?m0,?null)).intValue();???
  • ??}???
  • ????
  • ??public?final?String?toString(){?????
  • ??????return?((String)this.h.invoke(this,?m2,?null));???
  • ??}????
  • }???

  • 為了便于使代碼變得更簡介,更容易理解,上面的代碼中我把所有的異常檢測語句去掉了。

    從代碼中我們可以看出,代理實例類中關聯著一個InvocationHandler類型的成員變量h,當代理實例的方法被調用時事實上是調用了h對象的invoke方法,

    從而實現了上面我們所說的——“當委托類(如Hello類)的某個方法被調用時,我們能夠將這個方法對象(Method)傳遞給我們的invoke方法,然后通過調用invoke方法實現我們需要的代理操作”。

    (三)動態代理的拓展應用——Spring AOP

    正如上面分析,我們可以通過動態代理來為我們的業務方法加上日志記錄,同理,我們也可以通過動態代理實現對業務方法的事務控制(比如在方法前加上beginTransation,在方法后加上commit)。

    Spring中使用AOP(面向切面編程)實現事務控制的原理便是:通過的動態代理的機制,動態生成我們需要的代理實例,然后通過依賴注入,在運行時將這些代理實例注入到對應的委托類的對象中。

    總結

    以上是生活随笔為你收集整理的深度解析JAVA动态代理设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

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