什么是com.sun.proxy。$ Proxy

我已经看到,当错误发生在不同的框架(例如实现EJB规范的框架或某些JPA提供者)时,栈跟踪包含像com.sun.proxy.$Proxy这样的类。 我知道代理是什么,但我正在寻找更多的技术和更具体的Java的答案。

  1. 他们是什么?
  2. 他们是如何创build的?
  3. 与JVM有什么关系? 他们是JVM实现特定的?
  1. 代理是在运行时创build和加载的类。 这些类没有源代码。 我知道你想知道如何让他们做一些事情,如果没有代码。 答案是,当你创build它们时,你需要指定一个实现InvocationHandler的对象,该对象定义了一个在调用代理方法时被调用的方法。

  2. 您可以使用该通话创build它们

     Proxy.newProxyInstance(classLoader, interfaces, invocationHandler) 

    参数是:

    1. classLoader 。 一旦这个类被生成,它将被加载这个类加载器。
    2. interfaces 。 必须都是接口的类对象的数组。 由此产生的代理实现所有这些接口。
    3. invocationHandler 。 这就是你的代理知道如何调用方法时该怎么做。 这是一个实现InvocationHandler的对象。 当调用任何支持的接口或hashCodeequalstoString的方法时,将在处理程序上调用方法invoke ,传递要调用的方法的Method对象和传递的参数。

    有关更多信息,请参阅Proxy类的文档。

  3. 每个版本1.3之后的JVM的实现都必须支持这些。 它们以特定于实现的方式加载到JVM的内部数据结构中,但保证能够工作。

他们是什么?

没什么特别的。 就像普通的Java类实例一样。

但是这些类是由java.lang.reflect.Proxy#newProxyInstance创build的Synthetic proxy classes

与JVM有什么关系? 他们是JVM实现特定的?

在1.3中介绍

http://docs.oracle.com/javase/1.3/docs/relnotes/features.html#reflection

它是Java的一部分。 所以每个JVM都应该支持它。

他们是如何创build的(Openjdk7源)?

简而言之:它们是使用JVM ASM技术创build的(在运行时定义javabyte代码)

东西使用相同的技术:

调用java.lang.reflect.Proxy#newProxyInstance之后会发生什么java.lang.reflect.Proxy#newProxyInstance

  1. 阅读源码可以看到newProxyInstance调用getProxyClass0来获得一个`Class

    `

  2. 在大量caching之后,它会调用神奇的ProxyGenerator.generateProxyClass ,它返回一个字节[]
  3. 调用ClassLoader的define class来加载生成的$Proxy Class(你所看到的类名)
  4. 只是实例,并准备使用

在神奇的sun.misc.ProxyGenerator中发生了什么

  1. 绘制一个类(字节码),将接口中的所有方法合并为一个
  2. 每种方法都是用相同的字节码来构build的

    1. 打电话给方法meth信息(存储时生成)
    2. 将信息传递给invocation handlerinvoke()
    3. invocation handlerinvoke()获得返回值
    4. 只是返回它
  3. 类(bytecode)以byte[]forms表示

如何画一个class

思考你的java代码被编译成字节码,只是在运行时做到这一点

谈话很便宜的显示你的代码

sun / misc / ProxyGenerator.java中的核心方法

generateClassFile

 /** * Generate a class file for the proxy class. This method drives the * class file generation process. */ private byte[] generateClassFile() { /* ============================================================ * Step 1: Assemble ProxyMethod objects for all methods to * generate proxy dispatching code for. */ /* * Record that proxy methods are needed for the hashCode, equals, * and toString methods of java.lang.Object. This is done before * the methods from the proxy interfaces so that the methods from * java.lang.Object take precedence over duplicate methods in the * proxy interfaces. */ addProxyMethod(hashCodeMethod, Object.class); addProxyMethod(equalsMethod, Object.class); addProxyMethod(toStringMethod, Object.class); /* * Now record all of the methods from the proxy interfaces, giving * earlier interfaces precedence over later ones with duplicate * methods. */ for (int i = 0; i < interfaces.length; i++) { Method[] methods = interfaces[i].getMethods(); for (int j = 0; j < methods.length; j++) { addProxyMethod(methods[j], interfaces[i]); } } /* * For each set of proxy methods with the same signature, * verify that the methods' return types are compatible. */ for (List<ProxyMethod> sigmethods : proxyMethods.values()) { checkReturnTypes(sigmethods); } /* ============================================================ * Step 2: Assemble FieldInfo and MethodInfo structs for all of * fields and methods in the class we are generating. */ try { methods.add(generateConstructor()); for (List<ProxyMethod> sigmethods : proxyMethods.values()) { for (ProxyMethod pm : sigmethods) { // add static field for method's Method object fields.add(new FieldInfo(pm.methodFieldName, "Ljava/lang/reflect/Method;", ACC_PRIVATE | ACC_STATIC)); // generate code for proxy method and add it methods.add(pm.generateMethod()); } } methods.add(generateStaticInitializer()); } catch (IOException e) { throw new InternalError("unexpected I/O Exception"); } if (methods.size() > 65535) { throw new IllegalArgumentException("method limit exceeded"); } if (fields.size() > 65535) { throw new IllegalArgumentException("field limit exceeded"); } /* ============================================================ * Step 3: Write the final class file. */ /* * Make sure that constant pool indexes are reserved for the * following items before starting to write the final class file. */ cp.getClass(dotToSlash(className)); cp.getClass(superclassName); for (int i = 0; i < interfaces.length; i++) { cp.getClass(dotToSlash(interfaces[i].getName())); } /* * Disallow new constant pool additions beyond this point, since * we are about to write the final constant pool table. */ cp.setReadOnly(); ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(bout); try { /* * Write all the items of the "ClassFile" structure. * See JVMS section 4.1. */ // u4 magic; dout.writeInt(0xCAFEBABE); // u2 minor_version; dout.writeShort(CLASSFILE_MINOR_VERSION); // u2 major_version; dout.writeShort(CLASSFILE_MAJOR_VERSION); cp.write(dout); // (write constant pool) // u2 access_flags; dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER); // u2 this_class; dout.writeShort(cp.getClass(dotToSlash(className))); // u2 super_class; dout.writeShort(cp.getClass(superclassName)); // u2 interfaces_count; dout.writeShort(interfaces.length); // u2 interfaces[interfaces_count]; for (int i = 0; i < interfaces.length; i++) { dout.writeShort(cp.getClass( dotToSlash(interfaces[i].getName()))); } // u2 fields_count; dout.writeShort(fields.size()); // field_info fields[fields_count]; for (FieldInfo f : fields) { f.write(dout); } // u2 methods_count; dout.writeShort(methods.size()); // method_info methods[methods_count]; for (MethodInfo m : methods) { m.write(dout); } // u2 attributes_count; dout.writeShort(0); // (no ClassFile attributes for proxy classes) } catch (IOException e) { throw new InternalError("unexpected I/O Exception"); } return bout.toByteArray(); } 

addProxyMethod

 /** * Add another method to be proxied, either by creating a new * ProxyMethod object or augmenting an old one for a duplicate * method. * * "fromClass" indicates the proxy interface that the method was * found through, which may be different from (a subinterface of) * the method's "declaring class". Note that the first Method * object passed for a given name and descriptor identifies the * Method object (and thus the declaring class) that will be * passed to the invocation handler's "invoke" method for a given * set of duplicate methods. */ private void addProxyMethod(Method m, Class fromClass) { String name = m.getName(); Class[] parameterTypes = m.getParameterTypes(); Class returnType = m.getReturnType(); Class[] exceptionTypes = m.getExceptionTypes(); String sig = name + getParameterDescriptors(parameterTypes); List<ProxyMethod> sigmethods = proxyMethods.get(sig); if (sigmethods != null) { for (ProxyMethod pm : sigmethods) { if (returnType == pm.returnType) { /* * Found a match: reduce exception types to the * greatest set of exceptions that can thrown * compatibly with the throws clauses of both * overridden methods. */ List<Class<?>> legalExceptions = new ArrayList<Class<?>>(); collectCompatibleTypes( exceptionTypes, pm.exceptionTypes, legalExceptions); collectCompatibleTypes( pm.exceptionTypes, exceptionTypes, legalExceptions); pm.exceptionTypes = new Class[legalExceptions.size()]; pm.exceptionTypes = legalExceptions.toArray(pm.exceptionTypes); return; } } } else { sigmethods = new ArrayList<ProxyMethod>(3); proxyMethods.put(sig, sigmethods); } sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, exceptionTypes, fromClass)); } 

关于生成代理方法的完整代码

  private MethodInfo generateMethod() throws IOException { String desc = getMethodDescriptor(parameterTypes, returnType); MethodInfo minfo = new MethodInfo(methodName, desc, ACC_PUBLIC | ACC_FINAL); int[] parameterSlot = new int[parameterTypes.length]; int nextSlot = 1; for (int i = 0; i < parameterSlot.length; i++) { parameterSlot[i] = nextSlot; nextSlot += getWordsPerType(parameterTypes[i]); } int localSlot0 = nextSlot; short pc, tryBegin = 0, tryEnd; DataOutputStream out = new DataOutputStream(minfo.code); code_aload(0, out); out.writeByte(opc_getfield); out.writeShort(cp.getFieldRef( superclassName, handlerFieldName, "Ljava/lang/reflect/InvocationHandler;")); code_aload(0, out); out.writeByte(opc_getstatic); out.writeShort(cp.getFieldRef( dotToSlash(className), methodFieldName, "Ljava/lang/reflect/Method;")); if (parameterTypes.length > 0) { code_ipush(parameterTypes.length, out); out.writeByte(opc_anewarray); out.writeShort(cp.getClass("java/lang/Object")); for (int i = 0; i < parameterTypes.length; i++) { out.writeByte(opc_dup); code_ipush(i, out); codeWrapArgument(parameterTypes[i], parameterSlot[i], out); out.writeByte(opc_aastore); } } else { out.writeByte(opc_aconst_null); } out.writeByte(opc_invokeinterface); out.writeShort(cp.getInterfaceMethodRef( "java/lang/reflect/InvocationHandler", "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;" + "[Ljava/lang/Object;)Ljava/lang/Object;")); out.writeByte(4); out.writeByte(0); if (returnType == void.class) { out.writeByte(opc_pop); out.writeByte(opc_return); } else { codeUnwrapReturnValue(returnType, out); } tryEnd = pc = (short) minfo.code.size(); List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes); if (catchList.size() > 0) { for (Class<?> ex : catchList) { minfo.exceptionTable.add(new ExceptionTableEntry( tryBegin, tryEnd, pc, cp.getClass(dotToSlash(ex.getName())))); } out.writeByte(opc_athrow); pc = (short) minfo.code.size(); minfo.exceptionTable.add(new ExceptionTableEntry( tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable"))); code_astore(localSlot0, out); out.writeByte(opc_new); out.writeShort(cp.getClass( "java/lang/reflect/UndeclaredThrowableException")); out.writeByte(opc_dup); code_aload(localSlot0, out); out.writeByte(opc_invokespecial); out.writeShort(cp.getMethodRef( "java/lang/reflect/UndeclaredThrowableException", "<init>", "(Ljava/lang/Throwable;)V")); out.writeByte(opc_athrow); }