JDK動態(tài)代理是這樣一種Class:
- 在運行時生成class,
- 在生成他時,必須提供一組interfaces給它,然后該class就會聲明它實現(xiàn)了這些interfaces.因此我們可以將該class的實例當做這些interfaces中的任何一個來用.
- 當然這個動態(tài)代理其實就是一個Proxy,它不會代替你做實質(zhì)性的工作,在生成他的實例時,你必須提供一個handler,由它接管實際的工作.
個人感覺這么去理解JDK動態(tài)代理:
- 1.誰按照什么規(guī)則,提供一個什么
- 2.替誰,具體做什么事.
映射一下
1.類加載器按照給定的接口規(guī)則,提供(創(chuàng)建)了一個代理類.
2.替目標類(被代理的類),具體做InvocationHandler實現(xiàn)的邏輯.
JDK動態(tài)代理 只能代理接口,核心代碼理解:
1.類加載器按照給定的接口規(guī)則,提供(創(chuàng)建)了一個代理類.
//返回代理類的一個實例,返回后的代理類可以當做被代理類使用
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
loader:類加載器,用于創(chuàng)建代理類實例
interfaces:實現(xiàn)的接口,標識代理類實現(xiàn)了哪些接口
invocationHandler:實際代理內(nèi)容的實現(xiàn).
2.替目標類(被代理的類),具體做InvocationHandler實現(xiàn)的邏輯.
//InvocationHandler 類中的方法
public Object invoke(Object obj,Method method,Object[] args)
obj: 一般指代理對象 代理對象已經(jīng)被創(chuàng)建了,傳遞到這里,
method:被代理的方法,指定的接口中的方法
args:該方法的參數(shù)數(shù)組.實際方法調(diào)用時候的實際參數(shù)數(shù)組
上述兩個方法位于java.lang.reflect包下,從包名看出屬于反射的范疇.
public interface Subject {
public void request();
}
public class RealSubject implements Subject {
public void request() {
System.out.println("From real subject");
}
}
public class DynamicSubject implements InvocationHandler {
private Object sub;
public DynamicSubject(Object obj){
this.sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//proxy 是代理對象,不是真實對象.
System.out.println("before calling: " + method);
//這里使用的sub是被代理的對象的實例.
method.invoke(sub,args);//sub:對象(對應(yīng)到面向?qū)ο笾袑嵗椒ㄖ械膖his) args:方法參數(shù)(對應(yīng)到類中的實例方法運行時參數(shù))
System.out.println(args == null);
System.out.println("after calling: " + method);
return null;
}
}
//JDK動態(tài)代理實現(xiàn)步驟
//1.創(chuàng)建一個實現(xiàn)接口InvocationHandler的類,它必須實現(xiàn)invoke方法
//2.創(chuàng)建被代理的類以及接口(類實現(xiàn)此接口)因為JDK動態(tài)代理的規(guī)則,必須有接口
//3.通過Proxy的靜態(tài)方法 newProxyInstance()創(chuàng)建一個代理
//4.通過代理調(diào)用方法.
public class TestProxy {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicSubject(realSubject);
Class<?> classType = handler.getClass();
Class<?>[] interfaces = realSubject.getClass().getInterfaces();
Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(),interfaces,handler);
subject.request();
System.out.println(subject.getClass());
}
}
運行結(jié)果:
before calling: public abstract void com.zto.learn.Subject.request()
From real subject
true
after calling: public abstract void com.zto.learn.Subject.request()
class com.sun.proxy.$Proxy0
通過這種方式,被代理的對象(RealSubject)可以在運行時動態(tài)概念,需要控制的接口(Subject接口)可以在運行時改變,控制的方式(DynamicSubject類)也 可以動態(tài)改變,從而實現(xiàn)了非常靈活的動態(tài)代理關(guān)系.