概述
Java 中代理分为两大类,一类是静态代理,另一类是动态代理。静态代理是针对需要被代理的类在编译之前就已经写好了对应的代理类,也就是说代理关系在编译之前就确立了。动态代理是针对目标类在程序运行期间自动生成的代理类,细分为有接口的代理类和无接口的代理类。JDK动态代理支持目标类有接口的情况,目标类没有接口无法为其生成代理类,能够为没有接口生成代理类的工具如 CGLIB 等。本篇文章将对JDK动态代理实现原理进行介绍。
示例
接口
1 2 3 4 5 6 7 8
| public interface IPrintf {
void print(String message); }
|
实现类
1 2 3 4 5 6 7
| public class PrintfImpl implements IPrintf {
@Override public void print(String message) { System.out.println("print: " + message); } }
|
代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class Client {
private static final IPrintf PRINTF = new PrintfImpl();
public static IPrintf getProxy() {
return (IPrintf) Proxy.newProxyInstance( PRINTF.getClass().getClassLoader(), PRINTF.getClass().getInterfaces(), new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before action ... "); Object result = method.invoke(PRINTF, args); System.out.println("after action ... "); return result; } } ); } }
|
测试
1 2 3 4 5 6 7 8
| public class ProxyTest { @Test public void test() { IPrintf proxy = Client.getProxy(); proxy.print("hello world!"); } }
|
打印结果

代理类
通过阿里开源 Java 应用诊断工具 Arthas 反编译代理类,结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
package com.sun.proxy;
import com.code.proxy.IPrintf; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy4 extends Proxy implements IPrintf { private static Method m1; private static Method m2; private static Method m0; private static Method m3;
public $Proxy4(InvocationHandler invocationHandler) { super(invocationHandler); }
static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("com.code.proxy.IPrintf").getMethod("print", Class.forName("java.lang.String")); return; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError(noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } }
public final boolean equals(Object object) { try { return (Boolean)this.h.invoke(this, m1, new Object[]{object}); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } }
public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } }
public final int hashCode() { try { return (Integer)this.h.invoke(this, m0, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } }
public final void print(String string) { try { this.h.invoke(this, m3, new Object[]{string}); return; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
|
通过上面反编译后的代理类代码不难看出,JDK 动态代理实现具有以下特点:
- 生成的代理类继承了 Proxy 类且实现了 目标类的接口,有参构造方法的参数类型是 InvocationHandler ,反射创建代理对象执行的就是该构造方法。
- 代理类通过反射为目标接口(接口列表)中的每个方法都映射一个 Method 对象。
- 代理类对接口中方法的实现逻辑都是通过 InvocationHandler.invoke 方法派发执行的,代理对象调用任何目标接口的方法时都会调用这个invoke方法,该方法中进行目标类的目标方法的调用,即每个方法执行逻辑都由第 2 步中的 Method 对象执行。
关于 JDK 动态代理使用就介绍完毕了,下面我们对底层实现原理进行说明。实现原理中的部分描述信息会引用到上述代码片段。
JDK 动态代理
Java 中需要在运行期动态的生成一个类并创建其对象,一般需要使用字节码技术和反射机制。JDK 动态代理通过java.lang.reflect.Proxy
提供了一种原生的动态代理模式,其底层通过对字节码的操作和反射的使用组装代理类,如前文中的 $Proxy4,最后通过反射创建代理对象。
JDK通过调用静态方法 Proxy.newProxyInstance()
创建动态代理,该方法需要三个参数:
- 类加载器
通常可以从已经被加载的对象中获取其类加载器。
- 接口列表
预期代理实现的接口列表。
- InvocationHandler 接口的实现
作为动态代理对象的调用处理器,即动态代理可以将所有调用派发到该调用处理器。因此,通常会向调用处理器的构造器中传入一个目标对象的引用,从而使得调用处理器在执行中介任务时可以将请求转发。
介绍完代理相关的概念和使用方式后,下面我们对 JDK 动态代理实现原理进行说明。
源码分析
Proxy
属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| +--- java.lang.reflect.Proxy
private static final Class<?>[] constructorParams = {InvocationHandler.class};
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
protected InvocationHandler h;
private Proxy() { }
protected Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; }
}
|
Proxy 中有 3 个核心属性,下面简单介绍:
- constructorParams
Proxy 中的有参构造器的参数,是个固定值即调用处理器 InvocationHandler
,生成的代理类都会调用 Proxy
这个父类的构造方法。
- proxyClassCache
缓存生成的代理类,用于提高效率。需要注意的是,KeyFactory 和 ProxyClassFactory 都是 Proxy 的内部类,前者用于返回接口对应的弱引用,后者根据指定的类加载器和接口列表生成代理类。
- h
调用处理器,该处理器会将代理对象的方法调用派发给目标方法。
内部类 KeyFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| private static final class KeyFactory implements BiFunction<ClassLoader, Class<?>[], Object> {
@Override public Object apply(ClassLoader classLoader, Class<?>[] interfaces) { switch (interfaces.length) { case 1: return new Key1(interfaces[0]); case 2: return new Key2(interfaces[0], interfaces[1]); case 0: return key0; default: return new KeyX(interfaces); } } }
|
KeyFactory 就一个工作,返回接口对应的弱引用信息,KeyN 继承了 WeakReference
类。
内部类 ProxyClassFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
private static final String proxyClassNamePrefix = "$Proxy";
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; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); }
if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); }
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } }
String proxyPkg = null; int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
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) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; }
long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString()); } } }
|
ProxyClassFactory 完成生成字节码的操作,是生成代理类的完整流程,具体工作如下:
- 根据目标类的接口类型确定生成代理类全路径名
- 执行 ProxyGenerator.generateProxyClass 方法,根据代理类名和接口生成代理类字节码数组或文件形式
- 调用 native 方法将代理类字节码数据转化为代理类 Class
ProxyGenerator
ProxyClassFactory.apply 通过调用 ProxyGenerator.generateProxyClass 方法组装代理类,对接口的 Class
对象、Method
对象进行拆解、封装进而生成字节码层面的方法、构造方法以及静态代码块。
属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| +--- ProxyGenerator
private static final boolean saveGeneratedFiles = (Boolean) AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
private static Method hashCodeMethod; private static Method equalsMethod; private static Method toStringMethod;
private String className; private Class<?>[] interfaces; private int accessFlags;
private ProxyGenerator.ConstantPool cp = new ProxyGenerator.ConstantPool();
private List<ProxyGenerator.FieldInfo> fields = new ArrayList();
private List<ProxyGenerator.MethodInfo> methods = new ArrayList();
private Map<String, List<ProxyGenerator.ProxyMethod>> proxyMethods = new HashMap(); private int proxyMethodCount = 0;
static { try { hashCodeMethod = Object.class.getMethod("hashCode"); equalsMethod = Object.class.getMethod("equals", Object.class); toStringMethod = Object.class.getMethod("toString"); } catch (NoSuchMethodException var1) { throw new NoSuchMethodError(var1.getMessage()); } }
private ProxyGenerator(String var1, Class<?>[] var2, int var3) { this.className = var1; this.interfaces = var2; this.accessFlags = var3; }
|
JDK 动态代理涉及到的基础类先介绍到这里,下面我们从 Proxy.newProxyInstance
入口出发,根据调用链逐步分析源代码。
newProxyInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| +--- Proxy
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); }
Class<?> cl = getProxyClass0(loader, intfs);
try { 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});
} 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); } }
|
Proxy.newProxyInstance
方法是生成代理对象的入口,下面对该方法的逻辑进行简单说明:
- 调用
getProxyClass0
方法根据指定的类加载器和接口列表获取代理类。这一步是整个代理逻辑的核心实现。
- 反射获取参数为
InvocationHandler
的代理类的构造方法,并保证该构造方法是可访问的。
- 通过 newInstance 方法反射创建代理对象,参数类型为
InvocationHandler
。
第 2、3 步都很容易理解,下面我们重点来分析获取代理类的 getProxyClass0
方法。
getProxyClass0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| +--- Proxy
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); }
return proxyClassCache.get(loader, interfaces); }
|
前文中有提到代理类缓存属性 WeakCache proxyClassCache
,它的主要作用就是先查找对应的代理类缓存,没有的话就通过 java.lang.reflect.Proxy.ProxyClassFactory#apply
方法创建代理类,该方法在前文中已经详细说明。下面我们对 ProxyGenerator.generateProxyClass
根据代理类名和接口生成代理类字节码数组或文件形式 这一步骤进行说明。
generateProxyClass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| +--- ProxyGenerator
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2); final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { try { int var1 = var0.lastIndexOf(46); Path var2; if (var1 > 0) { Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar)); Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class"); } else { var2 = Paths.get(var0 + ".class"); }
Files.write(var2, var4, new OpenOption[0]); return null; } catch (IOException var4x) { throw new InternalError("I/O exception saving generated file: " + var4x); } } }); }
return var4; }
|
generateProxyClass 方法用于根据代理类名称和接口列表生成预期的代理类的字节码(数组)信息,最后通过 JDK 的本地方法转化为具体的代理类。该方法支持通过配置JVM参数将目标代理类输出到文件中。
在分析 ProxyGenerator.generateClassFile
方法之前,我们先对涉及的核心类和方法进行简单说明。注意该方法整个流程比较复杂,本文只对整体逻辑进行说明,具体细节可以参考源代码。
ProxyMethod
方法代理类,用于拆解、封装 Method 的信息,作为后续方法字节码生成的数据来源。
属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| +--- ProxyGenerator private class ProxyMethod { public String methodName; public Class<?>[] parameterTypes; public Class<?> returnType; public Class<?>[] exceptionTypes; public Class<?> fromClass; public String methodFieldName;
private ProxyMethod(String var2, Class<?>[] var3, Class<?> var4, Class<?>[] var5, Class<?> var6) { this.methodName = var2; this.parameterTypes = var3; this.returnType = var4; this.exceptionTypes = var5; this.fromClass = var6; this.methodFieldName = "m" + ProxyGenerator.this.proxyMethodCount++; }
}
|
generateMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| +--- ProxyMethod private ProxyGenerator.MethodInfo generateMethod() throws IOException { String var1 = ProxyGenerator.getMethodDescriptor(this.parameterTypes, this.returnType);
ProxyGenerator.MethodInfo var2 = ProxyGenerator.this.new MethodInfo(this.methodName, var1, 17);
int[] var3 = new int[this.parameterTypes.length]; int var4 = 1; for (int var5 = 0; var5 < var3.length; ++var5) { var3[var5] = var4; var4 += ProxyGenerator.getWordsPerType(this.parameterTypes[var5]); } byte var7 = 0;
DataOutputStream var9 = new DataOutputStream(var2.code); ProxyGenerator.this.code_aload(0, var9);
var9.writeByte(180); var9.writeShort(ProxyGenerator.this.cp.getFieldRef("java/lang/reflect/Proxy", "h", "Ljava/lang/reflect/InvocationHandler;")); ProxyGenerator.this.code_aload(0, var9); var9.writeByte(178); var9.writeShort(ProxyGenerator.this.cp.getFieldRef(ProxyGenerator.dotToSlash(ProxyGenerator.this.className), this.methodFieldName, "Ljava/lang/reflect/Method;")); if (this.parameterTypes.length > 0) { ProxyGenerator.this.code_ipush(this.parameterTypes.length, var9); var9.writeByte(189); var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/Object")); for (int var10 = 0; var10 < this.parameterTypes.length; ++var10) { var9.writeByte(89); ProxyGenerator.this.code_ipush(var10, var9); this.codeWrapArgument(this.parameterTypes[var10], var3[var10], var9); var9.writeByte(83); } } else { var9.writeByte(1); } var9.writeByte(185); var9.writeShort(ProxyGenerator.this.cp.getInterfaceMethodRef("java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;")); var9.writeByte(4); var9.writeByte(0);
if (this.returnType == Void.TYPE) { var9.writeByte(87); var9.writeByte(177); } else { this.codeUnwrapReturnValue(this.returnType, var9); }
short var6; short var8 = var6 = (short) var2.code.size(); List var13 = ProxyGenerator.computeUniqueCatchList(this.exceptionTypes); if (var13.size() > 0) { Iterator var11 = var13.iterator(); while (var11.hasNext()) { Class var12 = (Class) var11.next(); var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(var12.getName())))); } var9.writeByte(191); var6 = (short) var2.code.size(); var2.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var7, var8, var6, ProxyGenerator.this.cp.getClass("java/lang/Throwable"))); ProxyGenerator.this.code_astore(var4, var9); var9.writeByte(187); var9.writeShort(ProxyGenerator.this.cp.getClass("java/lang/reflect/UndeclaredThrowableException")); var9.writeByte(89); ProxyGenerator.this.code_aload(var4, var9); var9.writeByte(183); var9.writeShort(ProxyGenerator.this.cp.getMethodRef("java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V")); var9.writeByte(191); }
if (var2.code.size() > 65535) { throw new IllegalArgumentException("code size limit exceeded"); } else { var2.maxStack = 10; var2.maxLocals = (short) (var4 + 1); var2.declaredExceptions = new short[this.exceptionTypes.length];
for (int var14 = 0; var14 < this.exceptionTypes.length; ++var14) { var2.declaredExceptions[var14] = ProxyGenerator.this.cp.getClass(ProxyGenerator.dotToSlash(this.exceptionTypes[var14].getName())); } return var2; } }
|
generateMethod 方法根据 ProxyMethod
信息,按照方法的构造组装代表字节码信息的 MethodInfo
,最终将该信息写入到输出流中。
MethodInfo
ProxyMethod 对象经过解析后会组装成 MethodInfo 对象,该对象封装了代理类中方法的字节码信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| +--- ProxyGenerator private class MethodInfo { public int accessFlags; public String name; public String descriptor; public short maxStack; public short maxLocals; public ByteArrayOutputStream code = new ByteArrayOutputStream(); public List<ProxyGenerator.ExceptionTableEntry> exceptionTable = new ArrayList(); public short[] declaredExceptions;
public MethodInfo(String var2, String var3, int var4) { this.name = var2; this.descriptor = var3; this.accessFlags = var4; ProxyGenerator.this.cp.getUtf8(var2); ProxyGenerator.this.cp.getUtf8(var3); ProxyGenerator.this.cp.getUtf8("Code"); ProxyGenerator.this.cp.getUtf8("Exceptions"); }
}
|
FieldInfo
FieldInfo 用于封装方法在代理类中的静态属性信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| +--- ProxyGenerator private class FieldInfo { public int accessFlags; public String name; public String descriptor;
public FieldInfo(String var2, String var3, int var4) { this.name = var2; this.descriptor = var3; this.accessFlags = var4; ProxyGenerator.this.cp.getUtf8(var2); ProxyGenerator.this.cp.getUtf8(var3); } public void write(DataOutputStream var1) throws IOException { var1.writeShort(this.accessFlags); var1.writeShort(ProxyGenerator.this.cp.getUtf8(this.name)); var1.writeShort(ProxyGenerator.this.cp.getUtf8(this.descriptor)); var1.writeShort(0); } }
|
介绍完必要的前置概念和类信息后,我们回到 ProxyGenerator.generateClassFile
方法,继续接着流程往下分析。
generateClassFile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| +--- ProxyGenerator
private byte[] generateClassFile() { this.addProxyMethod(hashCodeMethod, Object.class); this.addProxyMethod(equalsMethod, Object.class); this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces; int var2 = var1.length; int var3; Class var4; for (var3 = 0; var3 < var2; ++var3) { var4 = var1[var3]; Method[] var5 = var4.getMethods(); int var6 = var5.length; for (int var7 = 0; var7 < var6; ++var7) { Method var8 = var5[var7]; this.addProxyMethod(var8, var4); } }
Iterator var11 = this.proxyMethods.values().iterator(); List var12; while (var11.hasNext()) { var12 = (List) var11.next(); checkReturnTypes(var12); } Iterator var15; try {
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator(); while (var11.hasNext()) { var12 = (List) var11.next(); var15 = var12.iterator(); while (var15.hasNext()) { ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod) var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
this.methods.add(var16.generateMethod()); } }
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) { throw new InternalError("unexpected I/O Exception", var10); }
if (this.methods.size() > 65535) { throw new IllegalArgumentException("method limit exceeded"); } else if (this.fields.size() > 65535) { throw new IllegalArgumentException("field limit exceeded"); } else {
this.cp.getClass(dotToSlash(this.className)); this.cp.getClass("java/lang/reflect/Proxy");
var1 = this.interfaces; var2 = var1.length; for (var3 = 0; var3 < var2; ++var3) { var4 = var1[var3]; this.cp.getClass(dotToSlash(var4.getName())); } this.cp.setReadOnly();
ByteArrayOutputStream var13 = new ByteArrayOutputStream(); DataOutputStream var14 = new DataOutputStream(var13);
try { var14.writeInt(-889275714); var14.writeShort(0); var14.writeShort(49); this.cp.write(var14); var14.writeShort(this.accessFlags);
var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var14.writeShort(this.interfaces.length); Class[] var17 = this.interfaces; int var18 = var17.length; for (int var19 = 0; var19 < var18; ++var19) { Class var22 = var17[var19]; var14.writeShort(this.cp.getClass(dotToSlash(var22.getName()))); }
var14.writeShort(this.fields.size()); var15 = this.fields.iterator(); while (var15.hasNext()) { ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo) var15.next(); var20.write(var14); }
var14.writeShort(this.methods.size()); var15 = this.methods.iterator(); while (var15.hasNext()) { ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo) var15.next(); var21.write(var14); } var14.writeShort(0);
return var13.toByteArray(); } catch (IOException var9) { throw new InternalError("unexpected I/O Exception", var9); } } }
|
generateClassFile 方法逻辑还是比较复杂的,下面对主要流程进行说明:
- 将 Object 中的三大方法对象解析、组装成 ProxyMethod 对象。
- 将目标类的接口中的方法对象解析、组装成 ProxyMethod 对象。
- 生成构造方法字节码信息并封装到 MethodInfo 对象中。
- 将第 1、2 步骤中组装的 ProxyMethod 对象进行解析,生成代表该方法字段标识的 FieldInfo 对象并缓存起来,解析为该方法的字节码信息的 MethodInfo 对象并缓存起来。
- 根据第 1、2 步骤中组装的 ProxyMethod 对象生成静态代码块字节码信息并封装到 MethodInfo 对象中并缓存起来。
- 对代理类中的方法数量做限制。
- 依次将代理类相关类路径、接口路径、代理类名、Proxy名、接口名、FieldInfo信息、MehodInfo信息写入到字节输出流中。
- 生成代理类字节码数组
整个过程介绍完毕,下面对该过程中涉及的核心方法进行说明。
addProxyMethod
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| +--- ProxyGenerator
private void addProxyMethod(Method var1, Class<?> var2) { String var3 = var1.getName(); Class[] var4 = var1.getParameterTypes(); Class var5 = var1.getReturnType(); Class[] var6 = var1.getExceptionTypes();
String var7 = var3 + getParameterDescriptors(var4);
Object var8 = (List) this.proxyMethods.get(var7); if (var8 != null) { Iterator var9 = ((List) var8).iterator();
while (var9.hasNext()) { ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod) var9.next(); if (var5 == var10.returnType) { ArrayList var11 = new ArrayList(); collectCompatibleTypes(var6, var10.exceptionTypes, var11); collectCompatibleTypes(var10.exceptionTypes, var6, var11); var10.exceptionTypes = new Class[var11.size()]; var10.exceptionTypes = (Class[]) var11.toArray(var10.exceptionTypes); return; } } } else { var8 = new ArrayList(3); this.proxyMethods.put(var7, var8); }
((List) var8).add(new ProxyGenerator.ProxyMethod(var3, var4, var5, var6, var2)); }
|
上述方法用于将 Method
对象拆解、组装为 ProxyMethod
对象,为后续组装代理类的方法字节码做准备。
generateConstructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| +--- ProxyGenerator private ProxyGenerator.MethodInfo generateConstructor() throws IOException { ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<init>", "(Ljava/lang/reflect/InvocationHandler;)V", 1); DataOutputStream var2 = new DataOutputStream(var1.code); this.code_aload(0, var2); this.code_aload(1, var2); var2.writeByte(183); var2.writeShort(this.cp.getMethodRef("java/lang/reflect/Proxy", "<init>", "(Ljava/lang/reflect/InvocationHandler;)V")); var2.writeByte(177); var1.maxStack = 10; var1.maxLocals = 2; var1.declaredExceptions = new short[0]; return var1; }
|
generateConstructor 方法用于生成构造方法的字节码信息。
generateStaticInitializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| +--- ProxyGenerator private ProxyGenerator.MethodInfo generateStaticInitializer() throws IOException { ProxyGenerator.MethodInfo var1 = new ProxyGenerator.MethodInfo("<clinit>", "()V", 8); byte var2 = 1; byte var4 = 0; DataOutputStream var6 = new DataOutputStream(var1.code);
Iterator var7 = this.proxyMethods.values().iterator(); while (var7.hasNext()) { List var8 = (List) var7.next(); Iterator var9 = var8.iterator();
while (var9.hasNext()) { ProxyGenerator.ProxyMethod var10 = (ProxyGenerator.ProxyMethod) var9.next(); var10.codeFieldInitialization(var6); } }
var6.writeByte(177); short var3; short var5 = var3 = (short) var1.code.size(); var1.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var4, var5, var3, this.cp.getClass("java/lang/NoSuchMethodException"))); this.code_astore(var2, var6); var6.writeByte(187); var6.writeShort(this.cp.getClass("java/lang/NoSuchMethodError")); var6.writeByte(89); this.code_aload(var2, var6); var6.writeByte(182); var6.writeShort(this.cp.getMethodRef("java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); var6.writeByte(183); var6.writeShort(this.cp.getMethodRef("java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V")); var6.writeByte(191); var3 = (short) var1.code.size(); var1.exceptionTable.add(new ProxyGenerator.ExceptionTableEntry(var4, var5, var3, this.cp.getClass("java/lang/ClassNotFoundException"))); this.code_astore(var2, var6); var6.writeByte(187); var6.writeShort(this.cp.getClass("java/lang/NoClassDefFoundError")); var6.writeByte(89); this.code_aload(var2, var6); var6.writeByte(182); var6.writeShort(this.cp.getMethodRef("java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); var6.writeByte(183); var6.writeShort(this.cp.getMethodRef("java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V")); var6.writeByte(191); if (var1.code.size() > 65535) { throw new IllegalArgumentException("code size limit exceeded"); } else { var1.maxStack = 10; var1.maxLocals = (short) (var2 + 1); var1.declaredExceptions = new short[0]; return var1; } }
|
generateStaticInitializer 方法用于生成代理类的静态代码块信息。
至此,JDK 动态代理的整个流程介绍完毕。
小结
JDK 动态代理是针对接口做的代理,目标类没有实现接口是无法通过这个方式创建代理对象。通过拼接字节码生成类是十分灵活的,理论上不管是有接口的类还是普通类都是可以实现代理的,CGLIB 就是通过拼接字节码来实现非接口类的代理逻辑。