代理模式
給某個(gè)對(duì)象提供一個(gè)代理對(duì)象,并由代理對(duì)象控制對(duì)于原對(duì)象的訪問(wèn)
什么是動(dòng)態(tài)代理
運(yùn)行時(shí)動(dòng)態(tài)生成代理類
動(dòng)態(tài)代理我們需要些什么
- 業(yè)務(wù)接口(Interface)
業(yè)務(wù)的抽象表示 - 業(yè)務(wù)具體實(shí)現(xiàn)類(concreteManager)
實(shí)現(xiàn)業(yè)務(wù)接口,執(zhí)行具體的業(yè)務(wù)操作 - 業(yè)務(wù)代理類($proxy,在運(yùn)行的時(shí)候動(dòng)態(tài)生成的類)
進(jìn)行業(yè)務(wù)代理,調(diào)用業(yè)務(wù)代理操作類 - 業(yè)務(wù)代理操作類(proxyHandler,實(shí)現(xiàn)了InvocationHandler接口的類)
代理方法的直接調(diào)用者,通過(guò)InvocationHandler中的invoke方法直接發(fā)起代理 - 客戶端調(diào)用對(duì)象(client)
發(fā)起業(yè)務(wù)
接下來(lái)是具體實(shí)現(xiàn)
業(yè)務(wù)接口ICook
public interface ICook {
void dealWithFood();
void cook();
}
業(yè)務(wù)具體實(shí)現(xiàn)類CookManager
public class CookManager implements ICook {
@Override
public void dealWithFood() {
System.out.println("food had been dealed with");
}
@Override
public void cook() {
System.out.println("cook food");
}
}
業(yè)務(wù)代理操作類DynamicProxyHandler
public class DynamicProxyHandler implements InvocationHandler{
Object realCookManager;
DynamicProxyHandler(ICook realCookManager){
this.realCookManager = realCookManager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke start");
System.out.println(method.getName());
method.invoke(realCookManager,args);
System.out.println("invoke end");
return null;
}
}
客戶端
public class Main {
public static void main(String[] args){
CookManager cookManager = new CookManager();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(cookManager);
ICook iCook =(ICook)Proxy.newProxyInstance(dynamicProxyHandler.getClass().getClassLoader(),cookManager.getClass().getInterfaces(), dynamicProxyHandler);
//打印一下代理類的類名
System.out.println(iCook.getClass().getName());
iCook.dealWithFoot();
iCook.cook();
}
}
實(shí)現(xiàn)過(guò)程很簡(jiǎn)單,看一下輸出的結(jié)果吧
com.sun.proxy.$Proxy0
invoke start
dealWithFoot
food had been dealed with
invoke end
invoke start
cook
cook food
invoke end
輸出結(jié)果分析
輸出的業(yè)務(wù)代理類類名為$Proxy0,DynamicProxyHandler中的invoke方法被調(diào)用了,并且method.invoke方法會(huì)調(diào)用實(shí)現(xiàn)類中的具體實(shí)現(xiàn)方法,到這里我們其實(shí)就已經(jīng)完成了代理操作了,并且在DynamicProxyHandler的invoke中我們還可以添加自己的操作,比如打印個(gè)日志什么的,這里其實(shí)就是一次簡(jiǎn)單的應(yīng)用層級(jí)的hook的實(shí)現(xiàn)了。我們可以在客戶端發(fā)起調(diào)用的時(shí)候使用代理中的方法替換掉原有的具體實(shí)現(xiàn)方法并對(duì)其進(jìn)行擴(kuò)展,這樣我們?cè)诓桓淖冊(cè)袑?shí)現(xiàn)類的情況下增強(qiáng)了原有類的功能,符合開(kāi)閉原則。
知其然知其所以然,我們必須對(duì)自己有追求呀!動(dòng)態(tài)代理實(shí)現(xiàn)的技術(shù)點(diǎn)主要是反射,為了更好的理解其原理,看源碼是少不了的過(guò)程~~
來(lái),老板,上盤生肉!
我們從Proxy類中的newProxyInstance這個(gè)函數(shù)入手,為了更好的理解其原理,以下是精簡(jiǎn)后的代碼
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
//所有被實(shí)現(xiàn)的業(yè)務(wù)接口
final Class<?>[] intfs = interfaces.clone();
//尋找或生成指定的代理類
Class<?> cl = getProxyClass0(loader, intfs);
//通過(guò)反射類中的Constructor獲取其所有構(gòu)造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
//通過(guò)Constructor返回代理類的實(shí)例
return cons.newInstance(new Object[]{h});
}
先看看這三個(gè)參數(shù)loader,interfaces,h;ClassLoader是一個(gè)抽象類,作用是將字節(jié)碼文件加載進(jìn)虛擬機(jī)并生成相應(yīng)的class(注意是小寫的),這里得到的loader是其子類AppClassLoader(負(fù)責(zé)加載應(yīng)用層字節(jié)碼)的一個(gè)實(shí)例,interfaces就是被實(shí)現(xiàn)的那些業(yè)務(wù)接口,h是InvocationHandler接口的實(shí)例,具體代理操作就被放在這個(gè)InvocationHandler的invoke函數(shù)中。
接下來(lái)看看生成業(yè)務(wù)代理類的getProxyClass0(loader,intfs)的實(shí)現(xiàn)
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// proxyClassCache會(huì)緩存所有的代理類,如果緩存中有這個(gè)業(yè)務(wù)代理類,則會(huì)從緩存中取出,否則從ProxyClassFactory中生成
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory是Proxy中的內(nèi)部類,緩存中如果沒(méi)有這個(gè)代理類則會(huì)調(diào)用ProxyClassFactory中的apply方法生成
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 這兩個(gè)常量就是代理類名字的由來(lái)
private static final String proxyClassNamePrefix = "$Proxy";
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//這里就生成了我們要的字節(jié)碼形式的代理類
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
//defineClass0是個(gè)native方法
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
到這里業(yè)務(wù)代理類就生成了,我們?cè)倩氐絥ewProxyInstance方法中,它會(huì)將InvocationHandler的實(shí)例h傳入這個(gè)業(yè)務(wù)代理類實(shí)例中
return cons.newInstance(new Object[]{h});
由于業(yè)務(wù)代理類是以字節(jié)碼形式存在于內(nèi)存中,我們想要看到其全貌可以將其保存下來(lái)然后反編譯查看其源碼
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(iCook.getClass().getName(),cookManager.getClass().getInterfaces());
saveToFile(proxyClassFile);
最終我們業(yè)務(wù)代理類$Proxy0類是這樣的!
public final class $Proxy0 extends Proxy implements ICook {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void cook() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void dealWithFoot() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
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]);
m3 = Class.forName("com.company.ICook").getMethod("cook", new Class[0]);
m4 = Class.forName("com.company.ICook").getMethod("dealWithFoot", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
這個(gè)流程終于變得清晰了。
當(dāng)我們將業(yè)務(wù)接口ICook和業(yè)務(wù)代理操作類DynamicProxyHandler傳入Proxy中后,Proxy會(huì)為我們生成一個(gè)實(shí)現(xiàn)了ICook接口并繼承了Proxy的業(yè)務(wù)代理類$Proxy0。
在我們具體調(diào)用方法 iCook.dealWithFood()時(shí)它其實(shí)是調(diào)用了$Proxy0中的dealWithFood方法,然后再調(diào)用Proxy類的invoke方法,所以DynamicProxyHandler中的invoke方法才是最終執(zhí)行的方法,這個(gè)方法給了我們擴(kuò)展的可能并且最終我們實(shí)現(xiàn)了代理對(duì)象訪問(wèn)原對(duì)象的目的,也就是$Proxy0代理了CookManager。
我的第一篇博客+我拍的第一張感覺(jué)還不錯(cuò)的照片(ps功底略差。。。),希望以后可以堅(jiān)持下來(lái),分析可能有所不足,望不吝賜教!
