前言
代理模式(Proxy design pattern)可以分为静态代理和动态代理,两种代理模式本质都是对外隔离真实的业务类,并且对外通过代理类,引入代理类的附加功能。对于动态代理的理解,其动态性并不是表现在省去了编写代理类的代码的工作量,而是表现在当真实的业务类、接口类还未知的时候,就可以确定了代理类的行为。
源码分析
1 | // IFractory 接口 |
上面代码简单创建了 DynamicProxy
类继承了 InvocationHandler
类,并重写 InvocationHandler#invoke()
方法,然后在 TestDynamicProxy
类中创建真正的业务类,并通过 lDynamicProxy#createProxyInstance()
生成代理类对象,代理类对象通过调用 createProduct() 方法,间接地调用真正的业务类的真实业务,如上述代码。
我们需要分析动态代理是如何为我们创建代理(Proxy)类的,我们查看[注释 1 ]处的代码细节:
1 | // Proxy.java#newProxyInstance() |
方法 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
主要的作用是根据指定的接口返回对应的代理类对象。
在上面的 Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
方法中,我去掉了一些不重要的代码逻辑,这个方法主要的作用是通过 Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces)
生成一个代理类的 Class 类,然后通过反射运行时获取到该代理类的实例,具体代码如上。
在 [注释 2]处,通过查看 Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces)
方法的具体实现,可以发现返回的 Class 代理类是通过给定的类加载器、指定的类接口而生成的,在程序运行期间会存储在内存中,在再次需要的时候,直接返回,具体代码如下:
1 |
|
通过解读上面 Proxy#getProxyClass0(ClassLoader loader, Class<?>... interfaces)
的注释,可以知道:如果代理类的 Class 存在,则直接从内存中把 Class 返回,如果代理类不存在通过则通过 ProxyClassFactory
创建代理类。
那么,这时候我们心里面会有疑问,ProxyClassFactory
是如何创建代理类 Class 的呢?
带着疑问,我们继续沿着代码往下面读。通过查阅代码,我们发现 [注释 3] 处的 proxyClassCache
变量是 WeakCache<ClassLoader, Class<?>[], Class<?>>
类型的,并且通过 new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
初始化了该变量,并在初始化的同时,发现 ProxyClassFactory
这个创建代理类的重要参数,传入 WeakCache
构造方法的第二个参数,那么我们在往下阅读的时候,需要额外关注 WeakCache
的构造方法的第二个参数。通过阅读 WeakCache#get(K key, P parameter)
方法:
1 | public V get(K key, P parameter) { |
在 WeakCache#get(K key, P parameter)
的方法逻辑比较复杂,但比较重要的是在 [注释 4] 处,代码 supplier.get()
中, 可以通过代码知道,supplier
是通过 new Factory(key, parameter, subKey, valuesMap)
初始化的,因此我们可以阅读 Factory#get()
方法,代码如下:
1 | private final class Factory implements Supplier<V> { |
通过阅读代码,我们可以发现 Factory
是 WeakCache
的普通内部类。Factory
类的代码逻辑比较简单,我们主要看 [注释 5] 处,代码 valueFactory.apply(key, parameter)
返回的值,正是我们需要的代理类 Class 对象,那么 valueFactory
是什么呢?
通过再次阅读代码,我们可以发现,valueFactory
正是源码中 new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
的第二个参数 new ProxyClassFactory()
, 那么我们可以尝试推断:
1 | Class<?> proxy = proxyClassCache.get(loader, interfaces); |
当然,上面的等价只是抽离了很多相关的代码而推断出的结论,实际上并不可以编译的。那么我们现在只需要专注于 ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces)
方法,通过下面阅读源码:
1 |
|
当我们继续阅读 private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len)
方法的时候,发现其是一个本地方法,底层如何实现我们在这里就不深究了(主要是我懒)。
在 ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces)
方法中,主要是准备创建 Proxy 代理类的准备工作,并没有太多复杂难懂的代码。
那么 proxyClassFile
内容是怎样的呢?我们可以通过输入输出流,把 proxyClassFile
输出到 .class
类型的文件中,文件代码如下:
1 | // |
通过阅读生成的 $proxy0.class
源码,我们可以主要阅读 [注释 7] 处,super.h.invoke(this, m3, new Object[]{var1})
中,h
表示的是 Proxy#InvocationHandler
, 那么我们就可以得出:
1 | InvocationHandler#invoke( |
以上,是动态代理源码分析的主要内容,知道动态代理主要是通过代码在内存中,生成指定类加载器和类接口的代理对象,然后保存在内存中,在需要的时候返回指定的代理实例。
通过上述的代码分析,我们也可以知道,动态代理会占用一定的内存,而且效率相对于静态代理较低,但这样子避免了在未确定真实类、以及对应的接口的时候,就可以确定代理类的行为,从而可以分离代理类和真实业务类的耦合,可以很灵活地应用在不同的场景中。