动态代理Proxy原理讲解

最近在阅读Retrofit的源码,首先看到了Retrofit的创建方法:

public  T create(final Class service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }
 
  

其中Proxy.newProxyInstance()返回了传入的接口对象,可以直接使用,节省了自己实现接口、创建对象的步骤。这个接口对象是怎么创建的呢,里面都有哪些方法?怎么就实现了接口、创建对象呢?感觉很神奇,下面结合源码说下。
首先从方法入口开始:

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);
        try {
            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                cons.setAccessible(true);
                // END Android-removed: Excluded AccessController.doPrivileged call.
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

这个方法咋一看,类呢,实现方法呢。
返回值是cons.newInstance(new Object[]{h})方法,传入的参数InvocationHandler作为该方法的参数,然后cons是cl的对象的构造方法,继续看cl的生成是从getProxyClass0(loader, intfs);方法返回的
查看该方法:

private static Class getProxyClass0(ClassLoader loader,
                                           Class... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

这里可以看到proxyClassCache是一个WeakCache对象,其初始化代码为

private static final WeakCache[], Class>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

传入了两个对象:KeyFactory,ProxyClassFactory
这两个类都是Proxy的内部类,其中KeyFactory的作用是根据传入的接口数量,生成一个唯一的key值,然后实现了key值得equal方法和hashCode方法,这两个方法常常用去判断两个对象是否相等时用的函数,比如if(a1==b1),如果a1和b1的equal和hashCode方法返回值相等的话,则a1==b1为true。
(Ps:可以查看Proxy的内部类,Key1、Key2、KeyX,这是不是不符合命名规范啊。)
另外一个ProxyClassFactory就是今天的关键了。实现了BiFunction接口,所以内部只有一个apply();

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

            Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 */
                Class interfaceClass = null;
                try {
                	//加载传入的class类,由于initialize传入的是false,所里这里并没有初始化类,
                	//只能获取该类的相关信息
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 * 是否是接口,如果不是接口,则抛出异常
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 * 是否已经加载过该类,则抛出异常,去重
                 */
                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;

            /*
             * Record the package of a non-public proxy interface so that the
             * proxy class will be defined in the same package.  Verify that
             * all non-public proxy interfaces are in the same package.
             */
             //因为上面已经将加载的类put进了interfaces,所以这里可以获取相应的方法,属性等。
            for (Class intf : interfaces) {
                int flags = intf.getModifiers();
                //必须是public类
                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) {
                    //获取包名,如果两次包名不一样,则抛出一样,因为retrofit之传入一个service,所以这里不会抛出异常。
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use the default package.
                proxyPkg = "";
            }

            {
                // Android-changed: Generate the proxy directly instead of calling
                // through to ProxyGenerator.
                //开始组织实际的类。
                //首先添加方法,将接口数组中的所有方法都添加到methods以及equals、hashcode、toString方法
                List methods = getMethods(interfaces);
                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                判断是否存在方法名、参数相同,但是返回值不同的,因为如果存在这种方法,那么生成的实现类会出现编译错误(重载)
                validateReturnTypes(methods);
                //方法去重,并返回所有的异常信息
                List[]> 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();
                //构造实现类的名称,包名+$Proxy+num
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
				//交给native方法去构造
                return generateProxy(proxyName, interfaces, loader, methodsArray,
                                     exceptionsArray);
            }
        }

方法很长,为了方便阅读,请看注释。

那么什么时候调用的apply()方法,我们回到WeakCache的get方法中去看:
动态代理Proxy原理讲解_第1张图片
这段代码表达的意思就是,如果根据key所获取的对象已经存在了,则不加载,如果不存在,则去加载。
加载是通过内部类Factory的get()方法去代理实现的。具体方法就不贴了,这个其实就是WeakCache的实现。
WeakCache这个类的内部存储逻辑:(key, sub-key) -> value,对key和value都是弱引用,对sub-key是强引用,其中sub-key是根据key值生成的,也就是我们传入的KeyFactory对象生成的sub-key.
对于key的弱引用使用refQueue来实现,对于value的弱引用使用CacheValue来实现。


    private final ReferenceQueue refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    private final ConcurrentMap>> map
        = new ConcurrentHashMap<>();
    private final ConcurrentMap, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    private final BiFunction subKeyFactory;
    private final BiFunction valueFactory;

他是线程安全的类,因为其内部使用ConcurrentMap来实现缓存。
对于Proxy这个类来说,key就是classloader,value就是ProxyClassFactory.apply()返回的对象。

下面通过log具体看下这个对象的内容:这里借鉴了
这篇博客的内容。

动态代理Proxy原理讲解_第2张图片
这里可以看到起类名是$Proxy16,与上面的分析一致。
使用bolg中的打印方法,运行之后,打印结果如下:

$Proxy16 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
java.lang.reflect.Method m4;
java.lang.reflect.Method m2;
java.lang.reflect.Method m0;
java.lang.reflect.Method m3;
java.lang.reflect.Method m1;

void processBusiness();
int hashCode();
boolean equals(java.lang.Object);
java.lang.String toString();

}

从这里可以看出,有BusinessProcessor接口的方法,有hashCode\equals\toString三个方法。
那又有问题了,当我们调用processBussiness方法时,是如何回调到Retrofit.create()方法中的InvocationHandler这个对象呢。

首先看到Proxy16是继承自Proxy这个类,该类的构造方法

protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

然后还记得Proxy.newProxyInstance()的最后一句:

cons.newInstance(new Object[]{h});

在这里传了h对象,也就是说,我们传入的InvocationHandler对象其实是传给了Proxy。
下面是processBusiness的具体实现:

@Override
    public void processBusiness() {
         try {
             //构造参数数组, 如果有多个参数往后面添加就行了
             Object[] args = new Object[] {};
             h.invoke(this, m4, args);
         } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
         }
     }

这里调用了h.invoke方法,也就是我们在Retrofit.create方法中传入的方法。

注意:这里传入的是一个接口,如果传入的是多个接口,那么这里的$Proxy16就会继承多个接口,实现其方法。

到这里就写完了Proxy这个类是如何创建一个对象,并通过代理模式,将方法的调用传递给InvocationHandler,继而Retrofit通过ServiceMethod类来包装请求的。

这里用到了一些设计模式,比如外观模式,动态代理,工厂模式等。

你可能感兴趣的:(Android,Proxy,WeakCache,动态代理)