動態代理源碼閱讀

動態代理在靜態代理的基礎上提供了在運行時生成代理類的功能。因此相比於靜態代理不用自定義代理類了。

用法

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 方法,在這個方法中去反射調用對應的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章