代理模式(Proxy design pattern)可以分为静态代理和动态代理,两种代理模式本质都是对外隔离真实的业务类,并且对外通过代理类,引入代理类的附加功能。对于动态代理的理解,其动态性并不是表现在省去了编写代理类的代码的工作量,而是表现在当真实的业务类、接口类还未知的时候,就可以确定了代理类的行为。
// IFractory 接口 public interface IFractory { void createProduct(); } public class ToyFractory implements IFractory { @Override public void createProduct() { System.out.println("生产玩具的厂家"); } } public class DynamicProxy implements InvocationHandler { private IFractory mIFractory; public IFractory getIFractory() { return mIFractory; } public void setIFractory(IFractory pIFractory) { mIFractory = pIFractory; } public Object createProxyInstance(){ return Proxy.newProxyInstance(mIFractory.getClass().getClassLoader(), mIFractory.getClass().getInterfaces(), this); // 注释 1 } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object lInvoke = method.invoke(mIFractory, args); return lInvoke; } } public class TestDynamicProxy { public static void main(String[] args) { ToyFractory lToyFractory = new ToyFractory(); DynamicProxy lDynamicProxy = new DynamicProxy(); lDynamicProxy.setIFractory(lToyFractory); IFractory lProxyInstance = (IFractory) lDynamicProxy.createProxyInstance(); lProxyInstance.createProduct(); } } 复制代码
上面代码简单创建了 DynamicProxy
类继承了 InvocationHandler
类,并重写 InvocationHandler#invoke()
方法,然后在 TestDynamicProxy
类中创建真正的业务类,并通过 lDynamicProxy#createProxyInstance()
生成代理类对象,代理类对象通过调用 createProduct() 方法,间接地调用真正的业务类的真实业务,如上述代码。
我们需要分析动态代理是如何为我们创建代理(Proxy)类的,我们查看[注释 1 ]处的代码细节:
// Proxy.java#newProxyInstance() public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); // 克隆出一份class<?>[] 数组,避免后续的操作干扰到 interfaces数组;(Java 语言是值传递) final Class<?>[] intfs = interfaces.clone(); .... /* * Look up or generate the designated proxy class. */ // 注释 2 // 根据参数生成指定的代理类对象 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { ... final Constructor<?> cons = cl.getConstructor(constructorParams); ... if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } // 通过反射调用,生成代理类对象并返回 return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { ... } catch (InvocationTargetException e) { ... } catch (NoSuchMethodException e) { ... } } 复制代码
方法 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 代理类是通过给定的类加载器、指定的类接口而生成的,在程序运行期间会存储在内存中,在再次需要的时候,直接返回,具体代码如下:
... /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); ... /** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { // 接口数量不可以超过 65535 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 // 注释 3 return proxyClassCache.get(loader, interfaces); } 复制代码
通过解读上面 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)
方法:
public V get(K key, P parameter) { ... Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey // map 是 ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> 类型的 ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance // 注释 4 V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } 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)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } } 复制代码
在 WeakCache#get(K key, P parameter)
的方法逻辑比较复杂,但比较重要的是在 [注释 4] 处,代码 supplier.get()
中, 可以通过代码知道, supplier
是通过 new Factory(key, parameter, subKey, valuesMap)
初始化的,因此我们可以阅读 Factory#get()
方法,代码如下:
private final class Factory implements Supplier<V> { Factory(K key, P parameter, Object subKey, ConcurrentMap<Object, Supplier<V>> valuesMap) { this.key = key; this.parameter = parameter; this.subKey = subKey; this.valuesMap = valuesMap; } @Override public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { // 注释 5 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) // 把创建出的代理类 Class 存储在 CacheValue CacheValue<V> cacheValue = new CacheValue<>(value); // put into reverseMap // cacheValue 继续放进 reverseMap 里面; reverseMap.put(cacheValue, Boolean.TRUE); // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; } } 复制代码
通过阅读代码,我们可以发现 Factory
是 WeakCache
的普通内部类。 Factory
类的代码逻辑比较简单,我们主要看 [注释 5] 处,代码 valueFactory.apply(key, parameter)
返回的值,正是我们需要的代理类 Class 对象,那么 valueFactory
是什么呢?
通过再次阅读代码,我们可以发现, valueFactory
正是源码中 new WeakCache<>(new KeyFactory(), new ProxyClassFactory())
的第二个参数 new ProxyClassFactory()
, 那么我们可以尝试推断:
Class<?> proxy = proxyClassCache.get(loader, interfaces); // 等价于 Class<?> proxy = new ProxyClassFactory().apply(loader, interfaces); 复制代码
当然,上面的等价只是抽离了很多相关的代码而推断出的结论,实际上并不可以编译的。那么我们现在只需要专注于 ProxyClassFactory#apply(ClassLoader loader, Class<?>[] interfaces)
方法,通过下面阅读源码:
@Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, 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对象 Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } .... } // 代理类的包路径 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. */ for (Class<?> intf : interfaces) { 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) { // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * Choose a name for the proxy class to generate. */ // 数字类加操作,从数字 0 开始(原子操作) long num = nextUniqueNumber.getAndIncrement(); // 拼接代理类的名字,如 $Proxy0 ... String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ // 生成指定的代理类,这里是一个 byte 类型的数组 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { // 注释 6 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); } } 复制代码
当我们继续阅读 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
类型的文件中,文件代码如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import cn.xxx.proxy_2.IFractory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements IFractory { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } // 注释 7 public final void createProduct() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("cn.enjoyedu.proxy_2.IFractory").getMethod("createProduct"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } } 复制代码
通过阅读生成的 $proxy0.class
源码,我们可以主要阅读 [注释 7] 处, super.h.invoke(this, m3, new Object[]{var1})
中, h
表示的是 Proxy#InvocationHandler
, 那么我们就可以得出:
InvocationHandler#invoke( new Proxy(), Class.forName("cn.xxx.proxy_2.IFractory").getMethod("saleManTools", Class.forName("java.lang.String")), new Object[]{var1}) 复制代码
以上,是动态代理源码分析的主要内容,知道动态代理主要是通过代码在内存中,生成指定类加载器和类接口的代理对象,然后保存在内存中,在需要的时候返回指定的代理实例。
通过上述的代码分析,我们也可以知道,动态代理会占用一定的内存,而且效率相对于静态代理较低,但这样子避免了在未确定真实类、以及对应的接口的时候,就可以确定代理类的行为,从而可以分离代理类和真实业务类的耦合,可以很灵活地应用在不同的场景中。