获取Proxy生成的字节码

通过ProxyGenerator来查看Proxy生成出的class流。

  1. import sun.misc.ProxyGenerator;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. public class ProxyClassGenerator {
  5. public static void main(String[] args) throws IOException {
  6. generateFile(Cloneable.class);
  7. }
  8. static void generateFile(Class c) throws IOException {
  9. byte[] proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{c});
  10. FileOutputStream fileOutputStream = new FileOutputStream("./"+c.getName()+".class");
  11. fileOutputStream.write(proxy0s);
  12. fileOutputStream.close();
  13. }
  14. }

反编译Proxy生成的类

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. import java.lang.reflect.UndeclaredThrowableException;
  5. public final class $Proxy0 extends Proxy implements Cloneable {
  6. //通过反射来获取具体的实现方法
  7. private static Method m1;
  8. private static Method m2;
  9. private static Method m0;
  10. static {
  11. try {
  12. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  13. m2 = Class.forName("java.lang.Object").getMethod("toString");
  14. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  15. } catch (NoSuchMethodException var2) {
  16. throw new NoSuchMethodError(var2.getMessage());
  17. } catch (ClassNotFoundException var3) {
  18. throw new NoClassDefFoundError(var3.getMessage());
  19. }
  20. }
  21. /**
  22. * 构造器需要
  23. */
  24. public $Proxy0(InvocationHandler var1) throws {
  25. //调用Proxy(InvocationHandler h),将设置InvocationHandler成员变量h。
  26. super(var1);
  27. }
  28. public final boolean equals(Object var1) throws {
  29. try {
  30. //通过调用InvocationHandler.invoke方法来触发用户自定义行为。
  31. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  32. } catch (RuntimeException | Error var3) {
  33. throw var3;
  34. } catch (Throwable var4) {
  35. throw new UndeclaredThrowableException(var4);
  36. }
  37. }
  38. public final String toString() throws {
  39. try {
  40. return (String)super.h.invoke(this, m2, (Object[])null);
  41. } catch (RuntimeException | Error var2) {
  42. throw var2;
  43. } catch (Throwable var3) {
  44. throw new UndeclaredThrowableException(var3);
  45. }
  46. }
  47. public final int hashCode() throws {
  48. try {
  49. return (Integer)super.h.invoke(this, m0, (Object[])null);
  50. } catch (RuntimeException | Error var2) {
  51. throw var2;
  52. } catch (Throwable var3) {
  53. throw new UndeclaredThrowableException(var3);
  54. }
  55. }
  56. }

重新看Proxy#newProxyInstance

我把SecurityManager相关代码删除了,不影响代码实现的学习。

  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{
  2. //校验h不能为空。
  3. Objects.requireNonNull(h);
  4. final Class<?>[] intfs = interfaces.clone();
  5. /*
  6. * 查找或生成指定的代理类。
  7. */
  8. Class<?> cl = getProxyClass0(loader, intfs);
  9. /*
  10. * 使用指定的调用处理程序调用其构造函数。
  11. */
  12. try {
  13. final Constructor<?> cons = cl.getConstructor(constructorParams);
  14. final InvocationHandler ih = h;
  15. return cons.newInstance(new Object[]{h});
  16. } catch (IllegalAccessException|InstantiationException e) {
  17. throw new InternalError(e.toString(), e);
  18. } catch (InvocationTargetException e) {
  19. Throwable t = e.getCause();
  20. if (t instanceof RuntimeException) {
  21. throw (RuntimeException) t;
  22. } else {
  23. throw new InternalError(t.toString(), t);
  24. }
  25. } catch (NoSuchMethodException e) {
  26. throw new InternalError(e.toString(), e);
  27. }
  28. }

接下来就是研究getProxyClass0里面是个啥了,基于上面的试验,可以推断出这是一个生产代理类二进制流,并通过类加载器加载进JVM的方法。

  1. private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  2. private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
  3. if (interfaces.length > 65535) {
  4. throw new IllegalArgumentException("interface limit exceeded");
  5. }
  6. // If the proxy class defined by the given loader implementing
  7. // the given interfaces exists, this will simply return the cached copy;
  8. // otherwise, it will create the proxy class via the ProxyClassFactory
  9. return proxyClassCache.get(loader, interfaces);
  10. }

getProxyClass0方法只做了一次参数校验,看来具体实现在WeakCache里面。然后WeakCache里面七绕八绕之后,最终加载的实现是ProxyClassFactory的apply方法。

  1. public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
  2. //一长串对interfaces做了各种校验。
  3. Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
  4. for (Class<?> intf : interfaces) {
  5. /*
  6. * Verify that the class loader resolves the name of this
  7. * interface to the same Class object.
  8. */
  9. Class<?> interfaceClass = null;
  10. try {
  11. interfaceClass = Class.forName(intf.getName(), false, loader);
  12. } catch (ClassNotFoundException e) {
  13. }
  14. if (interfaceClass != intf) {
  15. throw new IllegalArgumentException(intf + " is not visible from class loader");
  16. }
  17. /*
  18. * Verify that the Class object actually represents an
  19. * interface.
  20. */
  21. if (!interfaceClass.isInterface()) {
  22. throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
  23. }
  24. /*
  25. * Verify that this interface is not a duplicate.
  26. */
  27. if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
  28. throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
  29. }
  30. }
  31. //生成代理类包名
  32. String proxyPkg = null; // package to define proxy class in
  33. int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
  34. /*
  35. * Record the package of a non-public proxy interface so that the
  36. * proxy class will be defined in the same package. Verify that
  37. * all non-public proxy interfaces are in the same package.
  38. */
  39. for (Class<?> intf : interfaces) {
  40. int flags = intf.getModifiers();
  41. if (!Modifier.isPublic(flags)) {
  42. accessFlags = Modifier.FINAL;
  43. String name = intf.getName();
  44. int n = name.lastIndexOf('.');
  45. String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
  46. if (proxyPkg == null) {
  47. proxyPkg = pkg;
  48. } else if (!pkg.equals(proxyPkg)) {
  49. throw new IllegalArgumentException(
  50. "non-public interfaces from different packages");
  51. }
  52. }
  53. }
  54. if (proxyPkg == null) {
  55. // if no non-public proxy interfaces, use com.sun.proxy package
  56. proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
  57. }
  58. //生成代理类名
  59. long num = nextUniqueNumber.getAndIncrement();
  60. String proxyName = proxyPkg + proxyClassNamePrefix + num;
  61. /*
  62. * ProxyGenerator出现了非常好
  63. * 生成指定的代理类。
  64. */
  65. byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
  66. try {
  67. return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
  68. } catch (ClassFormatError e) {
  69. /*
  70. * A ClassFormatError here means that (barring bugs in the
  71. * proxy class generation code) there was some other
  72. * invalid aspect of the arguments supplied to the proxy
  73. * class creation (such as virtual machine limitations
  74. * exceeded).
  75. */
  76. throw new IllegalArgumentException(e.toString());
  77. }
  78. }
  79. /**
  80. * 动态加载类
  81. * @param loader 类加载器
  82. * @param name 类名
  83. * @param b 二进制数组
  84. * @param off 数组起始
  85. * @param len 数组结束
  86. * @return
  87. */
  88. private static native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

关于native方法defineClass0

我翻了下OpenJDK8的源码,里面有调用(*env)->DefineClass(env, utfName, loader, body, length)方法来加载类,更底层的就不挖了。

  1. JNIEXPORT jclass JNICALL
  2. Java_java_lang_reflect_Proxy_defineClass0(JNIEnv *env,
  3. jclass ignore,
  4. jobject loader,
  5. jstring name,
  6. jbyteArray data,
  7. jint offset,
  8. jint length)
  9. {
  10. jbyte *body;
  11. char *utfName;
  12. jclass result = 0;
  13. char buf[128];
  14. if (data == NULL) {
  15. JNU_ThrowNullPointerException(env, 0);
  16. return 0;
  17. }
  18. /* Work around 4153825. malloc crashes on Solaris when passed a
  19. * negative size.
  20. */
  21. if (length < 0) {
  22. JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
  23. return 0;
  24. }
  25. body = (jbyte *)malloc(length);
  26. if (body == 0) {
  27. JNU_ThrowOutOfMemoryError(env, 0);
  28. return 0;
  29. }
  30. (*env)->GetByteArrayRegion(env, data, offset, length, body);
  31. if ((*env)->ExceptionOccurred(env))
  32. goto free_body;
  33. if (name != NULL) {
  34. jsize len = (*env)->GetStringUTFLength(env, name);
  35. jsize unicode_len = (*env)->GetStringLength(env, name);
  36. if (len >= (jsize)sizeof(buf)) {
  37. utfName = malloc(len + 1);
  38. if (utfName == NULL) {
  39. JNU_ThrowOutOfMemoryError(env, NULL);
  40. goto free_body;
  41. }
  42. } else {
  43. utfName = buf;
  44. }
  45. (*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName);
  46. VerifyFixClassname(utfName);
  47. } else {
  48. utfName = NULL;
  49. }
  50. result = (*env)->DefineClass(env, utfName, loader, body, length);
  51. if (utfName && utfName != buf)
  52. free(utfName);
  53. free_body:
  54. free(body);
  55. return result;
  56. }