動態代理在靜態代理的基礎上提供了在運行時生成代理類的功能。因此相比於靜態代理不用自定義代理類了。
用法
interface DemoListener {
fun demo(str: String)
}
class TestDemo : DemoListener {
override fun demo(str: String) {
println(str)
}
}
一個接口,一個實現類,如果使用靜態代理還需要創建一個代理類,在代理類中傳入實現類,然後進行代理,這樣就可以在調用接口方法的前後做一些改變了。
如果是動態代理要怎麼做呢?
fun main() {
val testDemo = TestDemo()
val proxy = Proxy.newProxyInstance(
DemoListener::class.java.classLoader,
arrayOf(DemoListener::class.java),
CallBack(testDemo)
) as DemoListener
proxy.demo("345")
}
class CallBack(val any: Any?) : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
println("代理前 -------->")
if (any == null) {
return null
}
val invoke = method?.invoke(any, args?.get(0))
println("完成代理 -------->")
return invoke
}
}
動態代理,這種是 java 已經弄好的,只需要調用方法即可。
需要傳入參數:classload ,接口 class 的數組,InvocationHandler 的實現。
最終在使用 proxy 調用 demo 方法的時候會執行到 Callback 中的 invoke 方法中。其實 demo 方法還是你自己調用的,只不過用的是反射,好處就是在代理的前後,可以處理一些必須要處理的邏輯。並且可以進行健壯性的判斷,例如被代理類是否爲 null 等。
使用場景
有些人會動態代理,但是不知道他的使用場景,經常在代碼中不知道如果使用,下面說一個非常典型的案例:
在 mvp 中,p 層 和 v 層需要進行交互。但是有一種情況比較棘手,如果 v 層被銷燬了,p 層不知道,然後繼續調用對應的方法,這種情況下就會導致空指針異常。
解決:使用動態代理,在調用 v 層方法的前面判斷一下 v 層是否爲空即可
/**
* 動態代理,如果 V 層爲 null。則取消調用
*
* @return
*/
public V getView() {
return (V) Proxy.newProxyInstance(viewRef.get().getClass().getClassLoader(), viewRef.get().getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (viewRef.get() != null && isArgs(args)) {
return method.invoke(viewRef.get(), args);
} else if (!isArgs(args)) {
XLog.e("更新 View 層參數獲取失敗:" + proxy.toString() + "方法名字爲:" + method.getName());
}
return null;
}
});
}
其中 viewRef 爲弱引用,裏面存放着 v 層接口實例。
源碼閱讀
1,到底幹了什麼,怎麼實現的。
2,學習一些源碼怎麼寫的。
3,如果不懂的代碼沒必要深究,發現偏了方向趕緊重新回到原點重新來
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
/*
* 生成一個代理類
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//創建代理類 的構造函數
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
//判斷如果不是 public 的則設置權限
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
// END Android-removed: Excluded AccessController.doPrivileged call.
}
//返回代理類的對象,
return cons.newInstance(new Object[]{h});
} catch (InvocationTargetException e) {
//........
}
}
上面首先生成了一個代理類,然後就調用代理類的構造,將 InvocationHandler 傳了進去
下面看一下代理類是怎樣生成的
//代理緩存
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
//獲取代理類
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//從緩存中獲取代理
return proxyClassCache.get(loader, interfaces);
}
public V get(K key, P parameter) {
//...
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
//如果獲取的是 null,創建一個新的 valuesMap
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
//調用 apply 方法生成代理類,subKey 就是代理類
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
//從 map 中獲取
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
//死循環
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
//創建工廠
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
//supplier 如果爲空,則表示從 map 中沒有獲取到,下面進行保存
//最終會循環到上面的return ,將 代理類返回出去
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//遍歷所有的接口
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
// 加載一個 class
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
//判斷 .....
//將 加載出來的 class put 進去
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* 拿到包名
*/
for (Class<?> intf : interfaces) {
//獲取修改,判斷是否 public
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 = "";
}
{
//獲取所有方法
List<Method> methods = getMethods(interfaces);
//排序
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);
//獲取異常
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
//代理名稱,num 是標誌,避免生成名字相同的代理名稱
// private static final String proxyClassNamePrefix = "$Proxy";
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 創建代理類
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
}
梳理一下流程:
首先調用 getProxyClass0 方法獲取代理類,其中,首先會獲取緩存,如果緩存不存在,則創建緩存。接着調用 apply 方法區生產一個代理類,在 apply 方法中會獲取到包名,包名則是 proxyPak + $proxy+標誌。 獲取所有的方法,獲取異常等,最終 通過 generateProxy 完成代理class 的牀,generateProxy 是 native 層的方法。
拿到 代理後將 InvocationHandler 傳入到了代理中,由此我們可以推斷 我們調用 newProxyInstance 返回代理類的方法的時候其實調用的就是 InvocationHandler 中的 invoke 方法。在 invoke 中 去反射調用我們需要調用的方法。
總結一下:
動態代理無非就是在程序運行的過程中動態的生成了一個 代理類,這個代理類接收一個接口。
我們在調用 newProxyInstance 方法的時候就會傳入一個 實現類。並且返回一個代理類
我們在使用 代理類的時候會將其強轉爲對應的實現接口。然後在調用對應的方法,其實這裏調用的是 實現類的 invoke 方法,在這個方法中去反射調用對應的方法。