通過代碼進(jìn)行理解:
1.接口
public interface Subject {? ? ??
? ? ? ? ? public void rent();? ? ??
? ? ? ? ? public void hello(String str);
? }
2.實現(xiàn)類
public class RealSubject implements Subject{?
? ? ? ? ? @Override
? ? ? ? ? ? public void rent(){? ? ? ??
? ? ? ? ? ? ? ? ?System.out.println("I want to rent my House!");? ??
? ? ? ? ? ? }
????????????@Override
????????????????publicvoidhello(String str){
????????????? ? ? ? System.out.println("Hello:"+str);? ??
????????????}? ??
}
3.代理類
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler{
????private Object subject;//這是要代理的真實對象
? ? public Dynamic Proxy(Object subject){
????????this.subject=subject;//給要代理的真實對象初始化
????}??
????@Override
????public Object invoke(Object proxy, Method method,Object[] args)throwsThrowable {
????????//第一個參數(shù)是指最終生成的代理對象酿矢,也就是所要代理的真實對象
????????// 第二個是代理的方法,也就是所要代理的真實對象的某個方法
????????// 第三個是參數(shù)蜜暑,也就是真實對象調(diào)用的方法(第二個參數(shù))所需要的參數(shù)System.out.println("before rent house");
????????//代理前的添加的自定義操作策肝,此處是為了更好的看到代理效果????????
? ? ? ? ?System.out.println("Method:"+method);
????????//真實對象的方法
????????method.invoke(subject,args);
????????//當(dāng)代理對象調(diào)用真實對象的方法時之众,其會自動的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進(jìn)行調(diào)用//個人理解就是代理對象調(diào)用真實對象的方法,就跳轉(zhuǎn)到真實對象的方法去執(zhí)行????
????????System.out.println("after rent house");//代理后的操作缀蹄,此處是為了更好的看到代理效果
????????return null;?
?????}
}
4.客戶端
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public classClient{
????????public static void main(Stringargs[]){? ??
????????????Subject realSubject=newRealSubject();//真實對象InvocationHandler ????????????handler=newDynamicProxy(realSubject);//代理對象
????????????????//Proxy這個類的作用就是用來動態(tài)創(chuàng)建一個代理對象的類缺前,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法
????????????Subject subject= (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),realSubject.getClass()
.getInterfaces(),handler);
? ?????????//第一個參數(shù)一個ClassLoader對象拯刁,定義了由哪個ClassLoader對象來對生成的代理對象進(jìn)行加載
????????????//第二個參數(shù)逝段,一個Interface對象的數(shù)組惹恃,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它朗儒,
????????????// 那么這個代理對象就宣稱實現(xiàn)了該接口(多態(tài))参淹,這樣我就能調(diào)用這組接口中的方法了。
????????????????// 為什么能定義這個類型的對象恳不,因為我們給這個代理對象提供了一組什么接口开呐,那么我這個代理對象就會實現(xiàn)了這組接口筐付,可以轉(zhuǎn)化為接口中的任意一個類型并且必須使用接口類型//第三個參數(shù),一個InvocationHandler對象沮尿,表示的是當(dāng)我這個動態(tài)代理對象在調(diào)用方法的時候较解,會關(guān)聯(lián)到哪一個InvocationHandler對象上
????????????System.out.println(subject.getClass().getName();
/**
? ? * 可能我以為返回的這個代理對象會是Subject類型的對象,或者是InvocationHandler的對象啡捶,結(jié)果卻不是奸焙,
? ? * 首先我們解釋一下為什么我們這里可以將其轉(zhuǎn)化為Subject類型的對象徒溪?原因就是在newProxyInstance這個方法的第二個參數(shù)上臊泌,
? ? * 我們給這個代理對象提供了一組什么接口揍拆,那么我這個代理對象就會實現(xiàn)了這組接口,
? ? * 這個時候我們當(dāng)然可以將這個代理對象強(qiáng)制類型轉(zhuǎn)化為這組接口中的任意一個播揪,因為這里的接口是Subject類型筒狠,所以就可以將其轉(zhuǎn)化為Subject類型了辩恼。
? ? * 同時我們一定要記住雇庙,通過 Proxy.newProxyInstance 創(chuàng)建的代理對象是在jvm運行時動態(tài)生成的一個對象,它并不是我們的InvocationHandler類型灶伊,
? ? * 也不是我們定義的那組接口的類型疆前,而是在運行是動態(tài)生成的一個對象,并且命名方式都是這樣的形式聘萨,以$開頭竹椒,proxy為中,最后一個數(shù)字表示對象的標(biāo)號米辐。
? ? */
????????????subject.rent();? ?????????
?????????????subject.hello(" world!");
/**
? ? *正好就是我們的Subject接口中的兩個方法胸完,這也就證明了當(dāng)我通過代理對象來調(diào)用方法的時候,
? ? * 起實際就是委托由其關(guān)聯(lián)到的 handler 對象的invoke方法中來調(diào)用翘贮,并不是自己來真實調(diào)用赊窥,而是通過代理的方式來調(diào)用的。
? ? */
????????}
}
5.newProxyInstance源碼
public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)? ?throws? ?IllegalArgumentException{
????????Objects.requireNonNull(h);
????????finalClass[] intfs = interfaces.clone();
?????????SecurityManager sm = System.getSecurityManager();
????????if(sm !=null) {
????????????checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
????????}
}