一、動(dòng)態(tài)代理簡介
1、什么是動(dòng)態(tài)代理?
通過反射機(jī)制動(dòng)態(tài)生成代理者對象的一種設(shè)計(jì)模式。
2、如何區(qū)分靜態(tài)代理和動(dòng)態(tài)代理?
- 靜態(tài)代理:程序運(yùn)行前,代理類已經(jīng)存在。
- 動(dòng)態(tài)代理:程序運(yùn)行前,代理類不存在,運(yùn)行過程中,動(dòng)態(tài)生成代理類。
3、為什么要使用動(dòng)態(tài)代理?
因?yàn)橐粋€(gè)靜態(tài)代理類只能服務(wù)一種類型的目標(biāo)對象,在目標(biāo)對象較多的情況下,會(huì)出現(xiàn)代理類較多、代碼量較大的問題。
而使用動(dòng)態(tài)代理動(dòng)態(tài)生成代理者對象能避免這種情況的發(fā)生。
二、動(dòng)態(tài)代理原理
先看一下動(dòng)態(tài)代理的 UML 圖:
圖片參考:設(shè)計(jì)模式(11)動(dòng)態(tài)代理 JDK VS CGLIB面試必問
1、通過
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
反射生成代理類對象。
2、調(diào)用動(dòng)態(tài)代理類對象方法,會(huì)回調(diào)
h.invoke(thisObject proxy, Method method, Object[] args); //最終調(diào)用的是 InvocationHandler 實(shí)現(xiàn)類中重寫的 invoke() 方法
3、最終,通過
method.invoke(Object obj, Object... args);
調(diào)用目標(biāo)對象的方法。
三、動(dòng)態(tài)代理實(shí)戰(zhàn)
1、使用步驟
(1)聲明目標(biāo)對象的抽象接口。
(2)聲明調(diào)用處理類(實(shí)現(xiàn) InvocationHandler 接口)。
(3)生成目標(biāo)對象類(實(shí)現(xiàn)目標(biāo)對象的抽象接口,這里由于每個(gè)代理類都繼承了 Proxy 類,又 Java 的單繼承特性,所以,只能針對接口創(chuàng)建代理類,不能針對類創(chuàng)建代理類,后續(xù)會(huì)解釋)。
(4)生成代理類對象。
(5)通過代理類對象,調(diào)用目標(biāo)對象的方法。
2、實(shí)戰(zhàn)代碼
// (1)聲明目標(biāo)對象的抽象接口
public interface ISubject {
void buy();
}
// (2)聲明調(diào)用處理類(實(shí)現(xiàn) InvocationHandler 接口)
public class InvocationHandlerImpl implements InvocationHandler{
private Object mRealObject;
public InvocationHandlerImpl(Object realObject) {
mRealObject = realObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy invoke, proxy = " + proxy.getClass() + ", realObject = " + mRealObject.getClass());
Object result = method.invoke(mRealObject, args);
return result;
}
}
// (3.1)實(shí)現(xiàn)目標(biāo)對象類 1
public class Buyer1 implements ISubject {
@Override
public void buy() {
System.out.println("buyer1 buy");
}
}
// (3.2)實(shí)現(xiàn)目標(biāo)對象類 2
public class Buyer2 implements ISubject {
@Override
public void buy() {
System.out.println("buyer2 buy");
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 在工程目錄下生成 $Proxy0 的 class 文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Buyer1 buyer1 = new Buyer1(); //創(chuàng)建目標(biāo)對象的對象
InvocationHandlerImpl invocationHandlerImpl1 = new InvocationHandlerImpl(buyer1); //創(chuàng)建調(diào)用處理類對象
//(4)生成代理類對象
ISubject buyer1Proxy = (ISubject) Proxy.newProxyInstance(buyer1.getClass().getClassLoader(), buyer1.getClass().getInterfaces(), invocationHandlerImpl1);
//(5)通過代理類對象,調(diào)用目標(biāo)對象的方法
buyer1Proxy.buy();
System.out.println("目標(biāo)對象1:" + buyer1.getClass());
System.out.println("代理對象1:" + buyer1Proxy.getClass());
Buyer2 buyer2 = new Buyer2();
InvocationHandlerImpl invocationHandlerImpl2 = new InvocationHandlerImpl(buyer2);
ISubject buyer2Proxy = (ISubject) Proxy.newProxyInstance(buyer2.getClass().getClassLoader(), buyer2.getClass().getInterfaces(), invocationHandlerImpl2);
buyer2Proxy.buy();
System.out.println("目標(biāo)對象2:" + buyer2.getClass());
System.out.println("代理對象2:" + buyer2Proxy.getClass());
}
}
我們運(yùn)行一下這個(gè) Demo,運(yùn)行結(jié)果如下:
proxy invoke, proxy = class com.sun.proxy.$Proxy0, realObject = class com.trampcr.proxy.Buyer1
buyer1 buy
目標(biāo)對象1:class com.trampcr.proxy.Buyer1
代理對象1:class com.sun.proxy.$Proxy0
proxy invoke, proxy = class com.sun.proxy.$Proxy0, realObject = class com.trampcr.proxy.Buyer2
buyer2 buy
目標(biāo)對象2:class com.trampcr.proxy.Buyer2
代理對象2:class com.sun.proxy.$Proxy0
從日志中可以看到代理類是 com.sun.proxy.$Proxy0,我們都知道動(dòng)態(tài)代理是動(dòng)態(tài)生成代理類對象,如果能看到動(dòng)態(tài)生成的這個(gè)代理類,是不是能更好的理解動(dòng)態(tài)代理的原理?
細(xì)心的同學(xué)可能已經(jīng)看到以上代碼中有一行比較特殊的代碼,這行代碼的作用是把 sun.misc.ProxyGenerator.saveGeneratedFiles 這個(gè)變量賦值為 true,這個(gè)變量為 true 時(shí),將會(huì)在工程目錄下生成 $Proxy0 的 class 文件(由于生成代理類的 ProxyGenerator 類在 sun.misc 包中,在 Android Studio 中無法調(diào)用,所以這里是在 Intellij 中寫的 Demo 進(jìn)行調(diào)用):
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
運(yùn)行后,在項(xiàng)目的 src 同級(jí)目錄下,會(huì)出現(xiàn)一個(gè) com.sun.proxy 包,這個(gè)包里放的就是動(dòng)態(tài)生成的代理類 $Proxy0。
package com.sun.proxy;
// $Proxy0 默認(rèn)繼承了 Proxy,所以這里解釋了“只能針對接口(ISubject)創(chuàng)建代理類,不能針對類創(chuàng)建代理類”。
public final class $Proxy0 extends Proxy implements ISubject {
private static Method m1;
private static Method m2;
private static Method m3;
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 buy() throws {
try {
// m3 = Class.forName("com.trampcr.proxy.ISubject").getMethod("buy", new Class[0]);
// 通過代理類訪問目標(biāo)對象的方法
// 最終會(huì)通過 super.h.invoke() 回調(diào)到我們重寫的 InvocationHandler 實(shí)現(xiàn)類的 invoke() 中。
super.h.invoke(this, m3, (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.trampcr.proxy.ISubject").getMethod("buy", 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());
}
}
}
看到這里我們對動(dòng)態(tài)代理的使用以及動(dòng)態(tài)生成的代理類有了一定認(rèn)識(shí),但對于代理對象是如何動(dòng)態(tài)生成的,還需要進(jìn)一步看源碼。
四、動(dòng)態(tài)代理源碼分析
生成動(dòng)態(tài)代理對象主要是通過:Proxy.newProxyInstance()。
這里的源碼分析分為兩個(gè)版本:JDK 1.7,JDK 1.8。
JDK 1.7
// loader:生成代理對象的類加載器(需要和目標(biāo)對象是同一個(gè)類加載器)
// interfaces:目標(biāo)對象實(shí)現(xiàn)的接口,代理類也需要實(shí)現(xiàn)這個(gè)接口
// h:InvocationHandler 的實(shí)現(xiàn)類對象,動(dòng)態(tài)代理對象調(diào)用目標(biāo)對象方法時(shí),最終會(huì)回調(diào) h.invoke()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException {
... //省略部分邏輯,直接看主要邏輯
// 1、通過 loader 和 interfaces 創(chuàng)建動(dòng)態(tài)代理類
Class<?> cl = getProxyClass0(loader, interfaces);
try {
// 2、通過反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)(參數(shù)類型是 InvocationHandler.class 類型)
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
// 3、通過動(dòng)態(tài)代理類的構(gòu)造函數(shù)和調(diào)用處理器對象創(chuàng)建代理類實(shí)例
return newInstance(cons, ih);
...
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
// loader:生成代理對象的類加載器
// interfaces:目標(biāo)對象實(shí)現(xiàn)的接口,以下簡稱接口
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
...
Class<?> proxyClass = null;
// 接口名稱數(shù)組,用于收集接口的名稱作為代理類緩存的 key
String[] interfaceNames = new String[interfaces.length];
// 接口集合,用于檢查是否重復(fù)的接口
Set<Class<?>> interfaceSet = new HashSet<>();
// 遍歷目標(biāo)對象實(shí)現(xiàn)的接口
for (int i = 0; i < interfaces.length; i++) {
// 獲取接口名稱
String interfaceName = interfaces[i].getName();
Class<?> interfaceClass = null;
try {
// 通過反射加載目標(biāo)類實(shí)現(xiàn)的接口到內(nèi)存中
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " is not visible from class loader");
}
...
// 如果接口重復(fù),拋出異常
if (interfaceSet.contains(interfaceClass)) {
throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
// 將接口名稱數(shù)組轉(zhuǎn)換為接口名稱列表
List<String> key = Arrays.asList(interfaceNames);
// 通過 Classloader 獲取或者創(chuàng)建一個(gè)代理類緩存
Map<List<String>, Object> cache;
// 將一個(gè) ClassLoader 映射到該 ClassLoader 的代理類緩存
// private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache = new WeakHashMap<>();
synchronized (loaderToCache) {
cache = loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap<>();
loaderToCache.put(loader, cache);
}
}
synchronized (cache) {
do {
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class<?>) ((Reference) value).get();
}
if (proxyClass != null) {
return proxyClass;
} else if (value == pendingGenerationMarker) {
// 正在創(chuàng)建代理類,等待,代理類創(chuàng)建完成后會(huì)執(zhí)行 notifyAll() 進(jìn)行通知
try {
cache.wait();
} catch (InterruptedException e) {
}
continue;
} else {
// 代理類為空,往代理類緩存中添加一個(gè) pendingGenerationMarker 標(biāo)識(shí),表示正在創(chuàng)建代理類
cache.put(key, pendingGenerationMarker);
break;
}
} while (true); //這是一個(gè)死循環(huán),直到代理類不為空時(shí),返回代理類
}
// 以下為生成代理類邏輯
try {
String proxyPkg = null;
// 遍歷接口的訪問修飾符,如果是非 public 的,代理類包名為接口的包名
for (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
String name = interfaces[i].getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果接口都是 public 的,則用 com.sun.proxy 作為包名,這個(gè)從 $Proxy0 類中可以看到
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
{
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 根據(jù)代理類全路徑和接口創(chuàng)建代理類的字節(jié)碼
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
try {
// 根據(jù)代理類的字節(jié)碼生成代理類
proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
// 創(chuàng)建的所有代理類集合
// private static Map<Class<?>, Void> proxyClasses = Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
proxyClasses.put(proxyClass, null);
} finally {
synchronized (cache) {
if (proxyClass != null) {
// 創(chuàng)建好代理類后存到代理類緩存中
cache.put(key, new WeakReference<Class<?>>(proxyClass));
} else {
// 否則,清除之前存入的 pendingGenerationMarker 標(biāo)識(shí)
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
源碼有點(diǎn)多,總結(jié)一下動(dòng)態(tài)生成代理類對象的過程:
1、通過 loader 和 interfaces 創(chuàng)建動(dòng)態(tài)代理類(首先,根據(jù)代理類全路徑和接口創(chuàng)建代理類的字節(jié)碼,其次,根據(jù)代理類的字節(jié)碼生成代理類)。
2、通過反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)(參數(shù)類型是 InvocationHandler.class 類型)。
3、通過動(dòng)態(tài)代理類的構(gòu)造函數(shù)和調(diào)用處理器對象創(chuàng)建代理類實(shí)例。
最后,動(dòng)態(tài)創(chuàng)建的代理類可以看上邊貼過的代碼:$Proxy0。
JDK 1.8
// loader:生成代理對象的類加載器(需要和目標(biāo)對象是同一個(gè)類加載器)
// interfaces:目標(biāo)對象實(shí)現(xiàn)的接口,代理類也需要實(shí)現(xiàn)這個(gè)接口
// h:InvocationHandler 的實(shí)現(xiàn)類對象,動(dòng)態(tài)代理對象調(diào)用目標(biāo)對象方法時(shí),最終會(huì)回調(diào) h.invoke()
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
..
// clone 傳入的目標(biāo)對象實(shí)現(xiàn)的接口
final Class<?>[] intfs = interfaces.clone();
...
1、通過 loader 和 interfaces 創(chuàng)建動(dòng)態(tài)代理類
Class<?> cl = getProxyClass0(loader, intfs);
try {
...
// 2、通過反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)(參數(shù)類型是 InvocationHandler.class 類型)
final Constructor<?> cons = cl.getConstructor(constructorParams);
...
// 3、通過動(dòng)態(tài)代理類的構(gòu)造函數(shù)和調(diào)用處理器對象創(chuàng)建代理類實(shí)例
return cons.newInstance(new Object[]{h});
}
...
}
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
...
// 代理類緩存
// private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache =
// new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
// 根據(jù)傳入的 loader 和 interfaces 從緩存中獲取代理類,如果沒有緩存,通過 ProxyClassFactory 創(chuàng)建代理類
return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
...
// private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
Object cacheKey = CacheKey.valueOf(key, refQueue); //把 key 轉(zhuǎn)為 CacheKey
// map 的 key 是 Object 類型,key 的值支持 null
// private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// 關(guān)鍵點(diǎn)1、subKeyFactory 被傳進(jìn)來的是 new KeyFactory(),稍后看下 KeyFactory.apply()
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 這是一個(gè)死循環(huán),循環(huán)跳出條件是 value 不為空
// 關(guān)鍵點(diǎn)2、這里比較關(guān)鍵的點(diǎn)是 supplier.get(),這里會(huì)通過 ProxyClassFactory 創(chuàng)建代理類
while (true) {
if (supplier != null) {
// supplier 可能是一個(gè) Factory 或 CacheValue<V> 實(shí)例
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
// 關(guān)鍵點(diǎn)1、獲取 subKey(KeyFactory.apply())
// 這個(gè)方法主要是根據(jù)接口個(gè)數(shù)創(chuàng)建 subKey
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
case 1: return new Key1(interfaces[0]);
case 2: return new Key2(interfaces[0], interfaces[1]);
// private static final Object key0 = new Object();
case 0: return key0;
default: return new KeyX(interfaces);
}
}
// 關(guān)鍵點(diǎn)2、supplier.get() == WeakCache.Factory.get()
public synchronized V get() {
// 雙重校驗(yàn)
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// 出現(xiàn)這種情況的原因可能有:
// 1、被 CacheValue 代替
// 2、因?yàn)槭”灰瞥? return null;
}
V value = null;
try {
// 關(guān)鍵點(diǎn)3、valueFactory = ProxyClassFactory
// 真正創(chuàng)建代理類的代碼在 ProxyClassFactory.apply() 中
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) {
valuesMap.remove(subKey, this);
}
}
assert value != null;
CacheValue<V> cacheValue = new CacheValue<>(value);
if (valuesMap.replace(subKey, this, cacheValue)) {
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
return value;
}
// 關(guān)鍵點(diǎn)3、Proxy.ProxyClassFactory.apply():創(chuàng)建代理類
// 這個(gè)方法的代碼就很熟悉了,和 JDK 1.7 中 getProxyClass0() 方法幾乎一樣
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
...
}
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
JDK 1.7 和 JDK 1.8 中的源碼分析完了,我們發(fā)現(xiàn)其實(shí)生成代理類的方法都是一樣的,區(qū)別主要體現(xiàn)在緩存方式上,JDK 1.8 作了性能上的優(yōu)化,速度明顯比 1.7 提升了很多。
五、動(dòng)態(tài)代理在 Android 中的應(yīng)用
1、Android 的跨進(jìn)程通信中使用了動(dòng)態(tài)代理
比如 Activity 的啟動(dòng)過程,其實(shí)就隱藏了遠(yuǎn)程代理的使用。
2、Retrofit 中 create() 方法通過動(dòng)態(tài)代理獲取接口對象。
這些場景可能不夠全面,大家可以在評論區(qū)補(bǔ)充,看到新的場景,我后續(xù)也會(huì)補(bǔ)充的。
參考: