關於java動態代理模式
阿新 • • 發佈:2018-12-23
1. 動態代理
- 動態代理就是通過代理類是代理類與相關介面不直接發生聯絡,而在執行期(Runtime)實現動態關聯。
- 動態代理主要用到java.lang.reflect包中的兩個類,InvocationHandler介面和Proxy類。
- 動態代理相較於靜態代理最大的不同就是:動態代理的代理類不需要手動生成,該代理類是在執行期間動態生成的,這個動態生成的代理類已經實現代理物件的相關介面(Interface)。在生成代理類的同時,必須提供一個handler,這個handler有InvocationHandler提供,同時用來接管實際的工作。
2. InvocationHandler介面
(1)介面宣告:
public interface InvocationHandler
- 每一個動態代理類都必須實現InvocationHandler介面,InvocationHandler是代理例項(代理的真實物件),的呼叫處理程式實現的介面,當通過代理例項呼叫一個方法的時候,該方法的呼叫就會指派到它呼叫處理程式(InvocationHandler介面)的 invoke 方法。
(2)invoke方法宣告:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
引數意義:Object proxy: 指代所代理的真實物件,也就是真實物件的代理
Method method: 指代所呼叫的真實物件的某個方法的Method物件
Object[] args: 指代所代理的真實物件某個方法的引數
3. Proxy類
(1)類宣告:
public class Proxy extends Object implements Serializable
- Proxy 提供用於建立動態代理類和例項的靜態方法,它還是由這些方法建立的所有動態代理類的超類(JDK).
- Proxy類根據已經提供的相關介面和被代理的類就可以利用反射機制得到實現的方法,根據Proxy類的newProxyInstance(...)方法生成代理類。
(2)newProxyInstance方法宣告:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
引數意義:
ClassLoader loader: 類載入器,就是把動態生成的代理類的位元組碼檔案載入到JVM虛擬機器中,一般使用被代理類的類載入器
Class<?>[] interfaces:為代理物件提供的介面,就是被代理類實現的介面
InvocationHandler h: 當代理物件呼叫方法的時候關聯到InvocationHandler物件上,也就是前面說的*呼叫處理程式*(有待更深理解)
4.動態代理模式實現
package com.manu;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TestTrendsProxy {
public static void main(String[] args) {
Subject man = new Man();
Proxy p = new Proxy(man);
//通過java.lang.reflect.newProxyInstance(...)方法獲得真實物件的代理物件
Subject subject = (Subject)java.lang.reflect.Proxy.newProxyInstance(man.getClass().getClassLoader(), man.getClass().getInterfaces(), p);
//通過代理物件呼叫真實物件相關介面中實現的方法,這個時候就會跳轉到這個代理物件所關聯的handler的invoke()方法去執行
subject.shopping();
//獲得真實物件的代理物件所對應的Class物件的名稱,用字串表示
System.out.println(subject.getClass().getName());
//呼叫處理程式的表示
InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(subject);
System.out.println(handler);
}
}
//被代理人和代理人要執行的動作
interface Subject{
void shopping();
}
//被代理類
class Man implements Subject{
private String name="Tom";
public void shopping() {
System.out.println(name+"要去買東西...");
}
}
//代理類
class Proxy implements InvocationHandler{
private Object target;//要代理的真實物件
public Proxy(Subject target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy:"+proxy.getClass().getName());
System.out.println("購買之前的評估工作...");
method.invoke(target, args);
System.out.println("購買之後的滿意度調查...");
return null;
}
}
下面是執行結果:
執行結果:
proxy:com.manu.$Proxy0
購買之前的評估工作...
Tom要去買東西...
購買之後的滿意度調查...
com.manu.$Proxy0
[email protected]6bc7c054
執行結果中出現的$Proxy0是subject.getClass().getName())得到的,返回的是類的名稱,這是在執行時動態建立的,命名方式貌似是$Proxy+編號構成。整個代理過程主要體現在一個handler上。
如果選擇關注微信公眾號:jzman-blog,一起交流學習!