Proxy屬于代理型設(shè)計(jì)模式
定義:
為其它對象提供一種代理以控制對這個(gè)對象的訪問控制啸澡;在某些情況下拐邪,客戶不想或者不能直接引用另一個(gè)對象慰毅,這時(shí)候代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用。
作用:
1.實(shí)現(xiàn)無侵入式的代碼擴(kuò)展
2.解耦,交給代理處理
缺點(diǎn):
java系統(tǒng)中的動(dòng)態(tài)代理只能代理接口
應(yīng)用場景:
如Retrofit中請求服務(wù)的接口, 面向切面編程的Aop
Proxy.class
1.創(chuàng)建實(shí)現(xiàn)interfaces接口的對象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
loader: - 一個(gè)ClassLoader對象扎阶,定義了由哪個(gè)ClassLoader對象來對生成的代理對象進(jìn)行加載
interfaces: -一個(gè)Interface對象的數(shù)組汹胃,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它东臀,那么這個(gè)代理對象就宣稱實(shí)現(xiàn)了該接口(多態(tài))着饥,這樣我就能調(diào)用這組接口中的方法了
h: -一個(gè)InvocationHandler對象,表示的是當(dāng)我這個(gè)動(dòng)態(tài)代理對象在調(diào)用方法的時(shí)候惰赋,會關(guān)聯(lián)到哪一個(gè)InvocationHandler對象上
2.生成關(guān)于intfs接口實(shí)現(xiàn)的class對象
Class<?> cl = getProxyClass0(loader, intfs);
通過ProxyClassFactory創(chuàng)建此class對象
步驟一.生成接口實(shí)現(xiàn)類的字節(jié)數(shù)組
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
步驟二.生成實(shí)現(xiàn)類的class對象
private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len)
3.生成實(shí)現(xiàn)類對象
Constructor<?> cons = cl.getConstructor(constructorParams);
///////////////省略其他代碼///////////////
return cons.newInstance(new Object[]{h});
由此可知: 實(shí)現(xiàn)類對象是通過Proxy構(gòu)造后, 生成字節(jié)數(shù)組; 再調(diào)用底層代碼將字節(jié)數(shù)組轉(zhuǎn)換成class對象; 最后class對象通過 構(gòu)造器創(chuàng)建對象的方式宰掉,創(chuàng)建了實(shí)現(xiàn)類對象
InvocationHandler.class
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
proxy: - 指代我們所代理的那個(gè)真實(shí)對象
method: - 指代的是我們所要調(diào)用真實(shí)對象的某個(gè)方法的Method對象
args: - 指代的是調(diào)用真實(shí)對象某個(gè)方法時(shí)接受的參數(shù)
根據(jù)3 生成實(shí)現(xiàn)類對象,InvocationHandler作為了實(shí)現(xiàn)類的構(gòu)造參數(shù), 因此
InvocationHandler的invoke顯然和實(shí)現(xiàn)類對象的方法調(diào)用有關(guān), 到底是什么關(guān)系?
最好看看實(shí)現(xiàn)類長什么樣, 前面有提到 生成的字節(jié)數(shù)組, 因此可以將該字節(jié)數(shù)組生成一個(gè)類,展示出來
1.Subject是一個(gè)接口
public interface Subject {
/**
* 寫入字符串
* @param string
*/
void writeString(String string);
/**
* 讀取字符串
* @return
*/
String readString();
}
2.生成實(shí)現(xiàn)類方法
byte[] bytes = ProxyGenerator.generateProxyClass(
"InterfaceImpl", new Class[]{Subject.class}, Modifier.FINAL | Modifier.PUBLIC);
FilesKt.writeBytes(new File("InterfaceImpl.class"), bytes);
3.實(shí)現(xiàn)類
public final class InterfaceImpl extends Proxy implements Subject, Material {
/**
* m0,m1.. 為當(dāng)前的方法對象
*/
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m5;
private static Method m0;
public InterfaceImpl(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
/**
* 間接調(diào)用InvocationHandler對象中的invoke方法
*/
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String readString() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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 writeString(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String getColor() throws {
try {
return (String)super.h.invoke(this, m5, (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);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("chapter_pattern.agent.dynamic.Subject").getMethod("readString");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("chapter_pattern.agent.dynamic.Subject").getMethod("writeString", Class.forName("java.lang.String"));
m5 = Class.forName("chapter_pattern.agent.dynamic.Material").getMethod("getColor");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
顯然在調(diào)用實(shí)現(xiàn)類方法的時(shí)候,實(shí)際會通過InvocationHandler對象調(diào)用其重寫的invoke方法轨奄,通常我們會在重寫的invoke方法中去調(diào)用接口的實(shí)現(xiàn)類對象(注意:這個(gè)實(shí)現(xiàn)類對象不是我們通過字節(jié)碼生成的實(shí)現(xiàn)類對象, 而是業(yè)務(wù)中實(shí)現(xiàn)接口的類對象)
動(dòng)態(tài)代理簡單模型
代碼鏈接:https://github.com/A18767101271/java-/tree/master/src/chapter_pattern/agent/dynamic