我正试图研究http://www.eclipse.org/eclipselink/documentation/2.5/concepts/app_dev007.htm是否被应用到我的类中。
首先,下面是一些上下文…
很容易证明是否发生了静态织造。您可以使用javap -c MyCoolEntity查看某些MyCoolEntity.class类的反汇编。
在本例中:MyCoolEntity是一个描述JPA实体的类。可以在我们的构建过程中使用插件来“编织”它的字节码。
表示JPA实体关系的getter --在无编织字节码中--看起来像一个简单的字段查找:
public java.util.List<com.stackoverflow.Friend> getFriends();
Code:
0: aload_0
1: getfield #222 // Field friends:Ljava/util/List;
4: areturn但是,编织的字节码将调用委托给一个虚拟方法_persistence_get_*()。
public java.util.List<com.stackoverflow.Friend> getFriends();
Code:
0: aload_0
1: invokevirtual #640 // Method _persistence_get_friends:()Ljava/util/List;
4: areturn这种编织的字节码可以用来实现延迟查找(从数据库中按需获取相关实体)。
我希望我可以应用相同的逻辑来确定在我的应用程序中是否发生了动态编织。
我的理解是: Java代理在运行时转换类字节码。
有什么方法可以访问我的JPA实现的.class代理在运行时生成的JPA.class文件?是否可以连接到正在运行的JVM并对它保存在内存中的类执行反汇编?
免责声明:我的问题主要是“如何抓取和解压缩在运行时生成的.class文件”。回答子问题的方法可能还有其他,“动态编织发生了吗?”,但这部分并不是我问题的主要焦点。:)
值得注意的是:我使用的是EclipseLink 2.5.1和TomCat 8.5。
发布于 2017-03-10 17:09:09
您可以使用Apache Commons BCEL并执行如下操作:
package de.scrum_master.stackoverflow;
import java.io.IOException;
import java.io.InputStream;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
public class MethodDisassembler {
public static void main(String[] args) throws IOException {
Class<?> clazz = MethodDisassembler.class;
String classAsPath = clazz.getName().replace('.', '/') + ".class";
try (InputStream classStream = clazz.getClassLoader().getResourceAsStream(classAsPath)) {
ClassParser classParser = new ClassParser(classStream, classAsPath);
JavaClass javaClass = classParser.parse();
for (Method method : javaClass.getMethods())
System.out.println(method.getCode());
}
}
public void doSomething() {
sendEmail();
}
public void sendEmail() {
System.out.println("Sending e-mail");
}
}控制台日志:
Code(max_stack = 1, max_locals = 1, code_length = 5)
0: aload_0
1: invokespecial java.lang.Object.<init>:()V (8)
4: return
Attribute(s) =
LineNumber(0, 10)
LocalVariable(start_pc = 0, length = 5, index = 0:de.scrum_master.stackoverflow.MethodDisassembler this)
Code(max_stack = 5, max_locals = 12, code_length = 165)
0: ldc de.scrum_master.stackoverflow.MethodDisassembler (1)
2: astore_1
3: new <java.lang.StringBuilder> (19)
6: dup
7: aload_1
8: invokevirtual java.lang.Class.getName:()Ljava/lang/String; (21)
11: bipush 46
13: bipush 47
15: invokevirtual java.lang.String.replace:(CC)Ljava/lang/String; (27)
18: invokestatic java.lang.String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; (33)
21: invokespecial java.lang.StringBuilder.<init>:(Ljava/lang/String;)V (37)
24: ldc ".class" (40)
26: invokevirtual java.lang.StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; (42)
29: invokevirtual java.lang.StringBuilder.toString:()Ljava/lang/String; (46)
32: astore_2
33: aconst_null
34: astore_3
35: aconst_null
36: astore %4
38: aload_1
39: invokevirtual java.lang.Class.getClassLoader:()Ljava/lang/ClassLoader; (49)
42: aload_2
43: invokevirtual java.lang.ClassLoader.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream; (53)
46: astore %5
48: new <org.apache.bcel.classfile.ClassParser> (59)
51: dup
52: aload %5
54: aload_2
55: invokespecial org.apache.bcel.classfile.ClassParser.<init>:(Ljava/io/InputStream;Ljava/lang/String;)V (61)
58: astore %6
60: aload %6
62: invokevirtual org.apache.bcel.classfile.ClassParser.parse:()Lorg/apache/bcel/classfile/JavaClass; (64)
65: astore %7
67: aload %7
69: invokevirtual org.apache.bcel.classfile.JavaClass.getMethods:()[Lorg/apache/bcel/classfile/Method; (68)
72: dup
73: astore %11
75: arraylength
76: istore %10
78: iconst_0
79: istore %9
81: goto #105
84: aload %11
86: iload %9
88: aaload
89: astore %8
91: getstatic java.lang.System.out:Ljava/io/PrintStream; (74)
94: aload %8
96: invokevirtual org.apache.bcel.classfile.Method.getCode:()Lorg/apache/bcel/classfile/Code; (80)
99: invokevirtual java.io.PrintStream.println:(Ljava/lang/Object;)V (86)
102: iinc %9 1
105: iload %9
107: iload %10
109: if_icmplt #84
112: aload %5
114: ifnull #164
117: aload %5
119: invokevirtual java.io.InputStream.close:()V (92)
122: goto #164
125: astore_3
126: aload %5
128: ifnull #136
131: aload %5
133: invokevirtual java.io.InputStream.close:()V (92)
136: aload_3
137: athrow
138: astore %4
140: aload_3
141: ifnonnull #150
144: aload %4
146: astore_3
147: goto #162
150: aload_3
151: aload %4
153: if_acmpeq #162
156: aload_3
157: aload %4
159: invokevirtual java.lang.Throwable.addSuppressed:(Ljava/lang/Throwable;)V (97)
162: aload_3
163: athrow
164: return
Exception handler(s) =
From To Handler Type
48 112 125 <Any exception>(0)
38 138 138 <Any exception>(0)
Attribute(s) =
LineNumber(0, 12), LineNumber(3, 13), LineNumber(33, 14), LineNumber(38, 14),
LineNumber(48, 15), LineNumber(60, 16), LineNumber(67, 17), LineNumber(91, 18),
LineNumber(102, 17), LineNumber(112, 19), LineNumber(164, 20)
LocalVariable(start_pc = 0, length = 165, index = 0:java.lang.String[] args)
LocalVariable(start_pc = 3, length = 162, index = 1:java.lang.Class clazz)
LocalVariable(start_pc = 33, length = 132, index = 2:java.lang.String classAsPath)
LocalVariable(start_pc = 48, length = 88, index = 5:java.io.InputStream classStream)
LocalVariable(start_pc = 60, length = 52, index = 6:org.apache.bcel.classfile.ClassParser classParser)
LocalVariable(start_pc = 67, length = 45, index = 7:org.apache.bcel.classfile.JavaClass javaClass)
LocalVariable(start_pc = 91, length = 11, index = 8:org.apache.bcel.classfile.Method method)
LocalVariableTypes(start_pc = 3, length = 162, index = 1:java.lang.Class<?>... clazz)
StackMap((FULL, offset delta=84, locals={(type=Object, class=[Ljava.lang.String;), (type=Object, class=java.lang.Class), (type=Object, class=java.lang.String), (type=Object, class=java.lang.Throwable), (type=Object, class=java.lang.Throwable), (type=Object, class=java.io.InputStream), (type=Object, class=org.apache.bcel.classfile.ClassParser), (type=Object, class=org.apache.bcel.classfile.JavaClass), (type=Bogus), (type=Integer), (type=Integer), (type=Object, class=[Lorg.apache.bcel.classfile.Method;)}), (SAME, offset delta=20), (FULL, offset delta=19, locals={(type=Object, class=[Ljava.lang.String;), (type=Object, class=java.lang.Class), (type=Object, class=java.lang.String), (type=Object, class=java.lang.Throwable), (type=Object, class=java.lang.Throwable), (type=Object, class=java.io.InputStream)}, stack items={(type=Object, class=java.lang.Throwable)}), (CHOP 1, offset delta=10), (SAME_LOCALS_1_STACK, offset delta=1, stack items={(type=Object, class=java.lang.Throwable)}), (SAME, offset delta=11), (SAME, offset delta=11), (CHOP 2, offset delta=1))
Code(max_stack = 1, max_locals = 1, code_length = 5)
0: aload_0
1: invokevirtual de.scrum_master.stackoverflow.MethodDisassembler.sendEmail:()V (124)
4: return
Attribute(s) =
LineNumber(0, 23), LineNumber(4, 24)
LocalVariable(start_pc = 0, length = 5, index = 0:de.scrum_master.stackoverflow.MethodDisassembler this)
Code(max_stack = 2, max_locals = 1, code_length = 9)
0: getstatic java.lang.System.out:Ljava/io/PrintStream; (74)
3: ldc "Sending e-mail" (127)
5: invokevirtual java.io.PrintStream.println:(Ljava/lang/String;)V (129)
8: return
Attribute(s) =
LineNumber(0, 27), LineNumber(8, 28)
LocalVariable(start_pc = 0, length = 9, index = 0:de.scrum_master.stackoverflow.MethodDisassembler this)我想你可以自己解决剩下的问题。
更新和免责声明:对不起,我已经要求对已检测的类执行此操作,即与磁盘上的原始类文件相比,类在类加载过程中发生了更改。在这种情况下,我建议编写自己的小型Java代理,并将它放在代理链中的编织代理(不管是什么,AspectJ或其他什么)之后,然后再次使用工具API本身或BCEL,以确定类以前是否被正确地检测过。
Update 2: 这里您看到了如何按照上面的建议从检测代理转储二进制类。您仍然可以决定是要将字节存储在磁盘上,还是要将它们缓冲在内存中的字节数组中,然后通过BCEL通过ByteArrayInputStream读取它们。但是,如果您在集成测试之外需要它,那么这似乎是设计得很好的。在生产运行时,您可能不想使用它,或者至少在引导应用程序时只将其作为快速烟雾测试使用。
https://stackoverflow.com/questions/42683150
复制相似问题