靜態代理&動態代理


 

代理設計在Java開發中使用較多的一種設計模式,所謂的代理設計就是指由一個代理主題來操作真實主題,真實主題執行具體的業務操作,而代理主題負責其他相關業務的處理。

先來看看靜態代理

1 package com.proxy.inter;
2 
3 /**
4  * 定義Demo接口
5  */
6 public interface Demo {
7     public void save();
8 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 
 5 /**
 6  * DemoImpl實現Demo接口並覆寫save()方法
 7  * 真實主題,執行具體業務
 8  */
 9 public class DemoImpl implements Demo {
10     public void save() {
11         System.out.println("調用save()方法");
12     }
13 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 /**
 5  * DemoImplProxy 也實現了Demo接口,並覆寫了save()方法,增加了自己的業務 
 6  * 代理主題,負責其他業務的處理
 7  */
 8 public class DemoImplProxy implements Demo {
 9     Demo demoImpl = new DemoImpl();
10     
11     public void save() {
12         System.out.println("開始記錄日志");
13         demoImpl.save();
14         System.out.println("開始結束日志");
15     }
16 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.Demo;
 4 
 5 /**
 6  * 開始記錄日志
 7  * 調用save()方法
 8  * 開始結束日志
 9  */
10 public class Test {
11     public static void main(String[] args) {
12         Demo demoImplProxy = new DemoImplProxy();
13         
14         demoImplProxy.save();
15     }
16 }

你會發現每個代理類只能為一個接口服務,這樣程序開發中必然會產生許多的代理類

所以我們就會想辦法可以通過一個代理類完成全部的代理功能,那么我們就需要用動態代理

在Java中要想實現動態代理機制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 類的支持

java.lang.reflect.InvocationHandler接口的定義如下:

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

Object proxy:被代理的對象

Method method:要調用的方法

Object[] args:方法調用時所需要參數

java.lang.reflect.Proxy類的定義如下:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

CLassLoader loader:類的加載器

Class<?> interfaces:得到全部的接口

InvocationHandler h:得到InvocationHandler接口的子類的實例

下面來看看動態代理的具體實現

1 package com.proxy.inter;
2 
3 /**
4  * 定義DemoFirst接口
5  */
6 public interface DemoFirst {
7     public void saveFirst();
8 }
 1 package com.proxy.impl;
 2 
 3 import com.proxy.inter.DemoFirst;
 4 
 5 /**
 6  * DemoFirstImpl實現DemoFirst接口,覆寫saveFirst()方法
 7  * 真實主題,負責執行具體業務 
 8  */
 9 public class DemoFirstImpl implements DemoFirst {
10 
11     @Override
12     public void saveFirst() {
13         System.out.println("調用saveFirst()方法");
14     }
15 
16 }
 1 package com.proxy.impl;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * InvocationHandlerImple實現InvocationHandler接口,覆寫invoke()方法
 8  * 代理主題的業務寫在invoke()方法中
 9  */
10 public class InvocationHandlerImpl implements InvocationHandler {
11 
12     private Object target;
13     
14     public InvocationHandlerImpl(Object target) {
15         this.target = target;
16     }
17     
18     @Override
19     public Object invoke(Object proxy, Method method, Object[] args)
20             throws Throwable {
21         System.out.println("target : " + target.getClass().getName());
22         System.out.println("proxy : " + proxy.getClass().getName());
23         System.out.println("method : " + method.getName());
24         System.out.println("args : " + args);
25         System.out.println("開始記錄日志");
26         Object obj = method.invoke(target, args);
27         System.out.println("結束記錄日志");
28         /*    
29          * System.out.println("obj : " + obj.getClass().getName());
30          * 本例中saveXXX方法沒有返回值所以obj會報空指針異常
31          */
32         return obj;
33     }
34 }
 1 package com.proxy.impl;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 import com.proxy.inter.DemoFirst;
 6 /*import com.proxy.inter.DemoSecond;*/
 7 
 8 public class Test {
 9     public static void main(String[] args) {
10         DemoFirst first = new DemoFirstImpl();
11         /*DemoSecond second = new DemoSecondImpl();*/
12 
13         //取得代理對象
14         DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first
15                 .getClass().getClassLoader(), first.getClass().getInterfaces(),
16                 new InvocationHandlerImpl(first));
17         //通過動態代理調用方法
18         firstProxy.saveFirst();
19 
20         /*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second
21                 .getClass().getClassLoader(), second.getClass().getInterfaces(), 
22                 new InvocationHandlerImpl(second));
23         secondProxy.saveSecond();*/
24     }
25 }

執行結果如圖:

如果我們需要動態代理demoSecond對象,只需要像上面注釋部分那樣即可

執行結果如圖:

我們會發現代理類Proxy會動態分配proxy對象,如圖$Proxy0,$Proxy1...

動態代理的應用在很多地方都由體現,比如在開源框架Spring中的AOP(面向切面編程)...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM