主要来自极客时间 《RPC实战与核心原理》
给 Hello 接口生成一个动态代理类,并调用接口 say() 方法,但真实返回的值居然是来自 Other 里面的 speak() 方法返回值。
// 要代理的接口 public interface Hello { String say(); } // 真实调用对象 public class Other { public String speak(){ return "i'm proxy"; } } // JDK代理类生成 public class HelloInvocationHandler implements InvocationHandler { private Object target; HelloInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] paramValues) { return ((Other)target).speak(); } } // 测试例子 public class TestProxy { public static void main(String[] args){ // 构建代理器 HelloInvocationHandler proxy = new HelloInvocationHandler(new Other()); ClassLoader classLoader = ClassLoaderUtils.getCurrentClassLoader(); // 把生成的代理类保存到文件 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); // 生成代理类 Hello test = (Hello) Proxy.newProxyInstance(classLoader, new Class[]{Hello.class}, proxy); // 方法调用 System.out.println(test.say()); } }
Hello.say
的执行会通过 InvocationHandler.invoke
被转到 Other.speak
。用AOP 里的术语 就是 Other.speak
是pointcut, InvocationHandler.invoke
除 Other.speak
之外的其它部分是advise。 InvocationHandler.invoke
最后会执行 method.invoke(target,args)
。但此处实例表明, InvocationHandler.invoke
可以执行任意逻辑,可以自己实现所有逻辑,也可以是完全不相关的类的 不相关的方法 , invoke 方法参数 更多是提供被代理 方法的信息。 public class Proxy implements java.io.Serializable { private static final Class<?>[] constructorParams = { InvocationHandler.class }; public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){ final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } // Look up or generate the designated proxy class. Class<?> cl = getProxyClass0(loader, intfs); // Invoke its constructor with the designated invocation handler. if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } 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); } }
Proxy 包括一个内部类 ProxyClassFactory
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>{ // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { Class<?> interfaceClass = null; interfaceClass = Class.forName(intf.getName(), false, loader); ... } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; ... 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. long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; // Generate the specified proxy class. byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } }
可以看到,ProxyClassFactory 显示生成了 Class文件 的byte[],然后通过defineClass0 加载到jvm 中。
sun.misc.ProxyGenerator.saveGeneratedFiles
控制是否把生成的字节码保存到本地磁盘。动态生成的类会保存在工程根目录下的 com/sun/proxy
目录里面,我们找到刚才生成的 $Proxy0.class,通过反编译工具打开 class 文件
package com.sun.proxy; import com.proxy.Hello; 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 Hello { private static Method m3; private static Method m1; private static Method m0; private static Method m2; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final String say() { try { return (String)this.h.invoke(this, m3, null); } catch (Error|RuntimeException error) { throw null; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final boolean equals(Object paramObject) { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException error) { throw null; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException error) { throw null; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException error) { throw null; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } static { try { m3 = Class.forName("com.proxy.Hello").getMethod("say", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError(noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } } }
综上 可以得到一个类图