Java 什么是 com.sun.proxy.$Proxy
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19633534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is com.sun.proxy.$Proxy
提问by Andrei I
I have seen that when errors occur deep in different frameworks (e.g frameworks implementing the EJB specification or some JPA providers) the stacktrace contain classes like com.sun.proxy.$Proxy
. I know what a Proxy is, but I am looking for a more technical and more java specific answer.
我已经看到,当错误发生在不同框架(例如,实现 EJB 规范的框架或某些 JPA 提供者)深处时,堆栈跟踪包含类似com.sun.proxy.$Proxy
. 我知道代理是什么,但我正在寻找更具技术性和更具体的 Java 答案。
- What are they?
- How are they created?
- What is there relationship to the JVM? Are they JVM implementation specific?
- 这些是什么?
- 它们是如何创建的?
- 和JVM有什么关系?它们是特定于 JVM 实现的吗?
采纳答案by tbodt
Proxies are classes that are created and loaded at runtime. There is no source code for these classes. I know that you are wondering how you can make them do something if there is no code for them. The answer is that when you create them, you specify an object that implements
InvocationHandler
, which defines a method that is invoked when a proxy method is invoked.You create them by using the call
Proxy.newProxyInstance(classLoader, interfaces, invocationHandler)
The arguments are:
classLoader
. Once the class is generated, it is loaded with this class loader.interfaces
. An array of class objects that must all be interfaces. The resulting proxy implements all of these interfaces.invocationHandler
. This is how your proxy knows what to do when a method is invoked. It is an object that implementsInvocationHandler
. When a method from any of the supported interfaces, orhashCode
,equals
, ortoString
, is invoked, the methodinvoke
is invoked on the handler, passing theMethod
object for the method to be invoked and the arguments passed.
For more on this, see the documentation for the
Proxy
class.Every implementation of a JVM after version 1.3 must support these. They are loaded into the internal data structures of the JVM in an implementation-specific way, but it is guaranteed to work.
代理是在运行时创建和加载的类。这些类没有源代码。我知道您想知道如果没有代码,如何让他们做某事。答案是,当你创建它们时,你指定了一个实现的对象
InvocationHandler
,它定义了一个在调用代理方法时调用的方法。您可以使用调用创建它们
Proxy.newProxyInstance(classLoader, interfaces, invocationHandler)
论据是:
classLoader
. 一旦生成了类,就会用这个类加载器加载它。interfaces
. 必须都是接口的类对象数组。生成的代理实现了所有这些接口。invocationHandler
. 这就是您的代理在调用方法时知道要做什么的方式。它是一个实现InvocationHandler
. 当调用来自任何受支持接口的方法 orhashCode
、equals
、 or 时toString
,将invoke
在处理程序上调用该方法,传递Method
要调用的方法的对象和传递的参数。
有关更多信息,请参阅
Proxy
该类的文档。1.3 版之后 JVM 的每个实现都必须支持这些。它们以特定于实现的方式加载到 JVM 的内部数据结构中,但保证可以工作。
回答by farmer1992
What are they?
这些是什么?
Nothing special. Just as same as common Java Class Instance.
没什么特别的。就像普通的 Java 类实例一样。
But those class are Synthetic proxy classes
created by java.lang.reflect.Proxy#newProxyInstance
但是这些类是Synthetic proxy classes
由java.lang.reflect.Proxy#newProxyInstance
What is there relationship to the JVM? Are they JVM implementation specific?
和JVM有什么关系?它们是特定于 JVM 实现的吗?
Introduced in 1.3
在 1.3 中引入
http://docs.oracle.com/javase/1.3/docs/relnotes/features.html#reflection
http://docs.oracle.com/javase/1.3/docs/relnotes/features.html#reflection
It is a part of Java. so each JVM should support it.
它是Java的一部分。所以每个JVM都应该支持它。
How are they created (Openjdk7 source)?
它们是如何创建的(Openjdk7 源代码)?
In short : they are created using JVM ASM tech ( defining javabyte code at runtime )
简而言之:它们是使用 JVM ASM 技术创建的(在运行时定义 javabyte 代码)
something using same tech:
使用相同技术的东西:
- asm( http://asm.ow2.org/)
- cglib( http://cglib.sourceforge.net/)
- asm( http://asm.ow2.org/)
- cglib( http://cglib.sourceforge.net/)
What happens after calling java.lang.reflect.Proxy#newProxyInstance
调用后会发生什么 java.lang.reflect.Proxy#newProxyInstance
- reading the source you can see newProxyInstance call
getProxyClass0
to obtain a `Class`
- after lots of cache or sth it calls the magic
ProxyGenerator.generateProxyClass
which return a byte[] - call ClassLoader
define class
to load the generated$Proxy
Class (the classname you have seen) - just instance it and ready for use
- 阅读源码你可以看到 newProxyInstance 调用
getProxyClass0
来获取一个`Class`
- 在大量缓存或某事之后,它调用
ProxyGenerator.generateProxyClass
返回字节 []的魔法 - 调用 ClassLoader
define class
加载生成的$Proxy
Class(你见过的类名) - 只需实例化即可使用
What happens in magic sun.misc.ProxyGenerator
在魔术 sun.misc.ProxyGenerator 中会发生什么
- draw a class(bytecode) combining all methods in the interfaces into one
each method is build with same bytecode like
- get calling Method meth info (stored while generating)
- pass info into
invocation handler
'sinvoke()
- get return value from
invocation handler
'sinvoke()
- just return it
the class(bytecode) represent in form of
byte[]
- 绘制一个类(字节码),将接口中的所有方法合二为一
每个方法都是用相同的字节码构建的
- 获取调用方法方法信息(生成时存储)
- 将信息传递给
invocation handler
'sinvoke()
- 从
invocation handler
's获取返回值invoke()
- 只需返回它
类(字节码)以以下形式表示
byte[]
How to draw a class
如何画一个班级
Thinking your java codes are compiled into bytecodes, just do this at runtime
认为您的 java 代码已编译为字节码,只需在运行时执行此操作
Talk is cheap show you the code
谈话很便宜 给你看代码
core method in sun/misc/ProxyGenerator.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));
}
Full code about gen the proxy method
生成代理方法的完整代码
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);
}