动态代理

1.静态代理

先看下代码:

    interface IHttp {
        void get();
    }

    class AHttp implements IHttp {
        @Override
        public void get() {
        }
    }

    class HttpProxy implements IHttp {
        AHttp aHttp = new AHttp();
        @Override
        public void get() {
            Log.d(...)
            aHttp.get();
        }
    }

    private void test() {
        IHttp iHttp = new HttpProxy();
        iHttp.get();
    }

静态代理的好处是:
在不改动原”实现方法”(aHttp.get())的情况下,直接插入”额外”的处理(Log.d(…))。
静态代理存在缺点:
假设存在IHttp2,IHttp3..等多个类似的接口,都需要在方法体里面打印Log日志(共同的需求),那么必须分别实现相应的HttpProxy代理类,不够灵活。

2.动态代理 动态代理可以弥补这个缺陷,代码如下

  private void test() {
//        IHttp iHttp = new HttpProxy();
//        iHttp.get();

        AHttp aHttp = new AHttp();
        //newProxyInstance可以创建一个实现了IHttp接口的对象
        IHttp iHttp2 = (IHttp) Proxy.newProxyInstance(IHttp.class.getClassLoader(), new Class[]{IHttp.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Log.e("IHttp", "执行HttpProxy..");
                        aHttp.get();
                        return proxy;
                    }
                });
        iHttp2.get();
    }

当 iHttp2.get()的时候,实际执行了InvocationHandler的invoke函数。使用动态代理,完全看不到代理类的生成过程,但确实在invoke()中完成了对get()函数的代理,这是怎么做到的呢,代理类又是怎么生成的呢?
我想只能查看Proxy.newProxyInstance一探究竟。
简化一下源码:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) {
        final Class<?>[] intfs = interfaces.clone();
        //获取代理类的Class类型
        Class<?> cl = getProxyClass0(loader, intfs);
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        cons.setAccessible(true);
        //利用反射,创建代理类对象
        return cons.newInstance(new Object[]{h});
    }

探究一下getProxyClass0()具体是怎么做的,这里用到了一个WeakCache对象,它是所有代理类的缓存,如果已经有了该代理类就直接使用,没有才会进行创建,然后缓存起来。
那么无缓存的时候具体怎么创建代理类呢,关键代码:

Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

subKeyFactory实际是Proxy的内部类ProxyClassFactory,重写了apply方法:

private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        @Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

//            1.对classLoader和interface做校验
//            2.获取目标接口(被代理方)的method相关属性,主要是返回值和Exception
//            3.对准备创建的代理类命名,$Proxy+num(已经创建的代理类数量)
//            4.最后通过generateProxy()函数创建字节码文件并创建出Class对象。generateProxy是一个native函数
            return generateProxy(proxyName, interfaces, loader, methodsArray,
                    exceptionsArray);

        }
    }

3.Android中常用的库Retrofit2就使用了动态代理
通常情况下,网络接口的请求方法都写在一个单独的接口中,比如(以下retrofit:2.8.1):

public interface IApiService {
    @GET("art/artlist")
    Flowable<BaseResponse<List<CodeArticleBean>>> getCodeDatas(@Query("page") int page,
                                                               @Query("row") int row,
                                                               @Query("type") int type);
}
 // getCodeDatas中包含了Http请求的各种信息,GET请求,接口Path,请求参数等,调用getCodeDatas的过程中,使用了动态代理:
  public <T> T create(final Class<T> service) {
    validateServiceInterface(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
 
   //通过反射获取method的注解,参数等。
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

在invoke()函数中统一处理Http的请求信息,由于只需要目标类IApiService中的方法注解和参数信息,所以这里不需要实例化IApiService对象(对比2中的AHttp实例)。顺带提一下,由于代理类是运行时系统生成的,所以Retrofit2中的接口参数的注解是RUNTIME运行时注解。

4.Debug查看代理类
回归上面2中的的例子,简单的修改一下

private void test() {
        //代理1
        IHttp iHttp1 = (IHttp) Proxy.newProxyInstance(IHttp.class.getClassLoader(), new Class[]{IHttp.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.e("IHttp", "执行了iHttp1");
                return proxy;
            }
        });
        //代理2
        IHttp2 iHttp2 = (IHttp2) Proxy.newProxyInstance(IHttp2.class.getClassLoader(), new Class[]{IHttp2.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Log.e("IHttp", "执行了iHttp2");
                return proxy;
            }
        });
        iHttp1.get();
        iHttp2.post();
    }

运行后:

可见生成的代理类分别为$Proxy0.class和$Proxy1.class,且位于项目的包名根目录下。