首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在_runtime_中计算Java类的反汇编?

如何在_runtime_中计算Java类的反汇编?
EN

Stack Overflow用户
提问于 2017-03-08 22:30:46
回答 1查看 569关注 0票数 2

我正试图研究http://www.eclipse.org/eclipselink/documentation/2.5/concepts/app_dev007.htm是否被应用到我的类中。

首先,下面是一些上下文…

很容易证明是否发生了静态织造。您可以使用javap -c MyCoolEntity查看某些MyCoolEntity.class类的反汇编。

在本例中:MyCoolEntity是一个描述JPA实体的类。可以在我们的构建过程中使用插件来“编织”它的字节码。

表示JPA实体关系的getter --在无编织字节码中--看起来像一个简单的字段查找:

代码语言:javascript
复制
public java.util.List<com.stackoverflow.Friend> getFriends();
  Code:
     0: aload_0
     1: getfield      #222                // Field friends:Ljava/util/List;
     4: areturn

但是,编织的字节码将调用委托给一个虚拟方法_persistence_get_*()

代码语言:javascript
复制
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。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-10 17:09:09

您可以使用Apache Commons BCEL并执行如下操作:

代码语言:javascript
复制
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");
  }
}

控制台日志:

代码语言:javascript
复制
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读取它们。但是,如果您在集成测试之外需要它,那么这似乎是设计得很好的。在生产运行时,您可能不想使用它,或者至少在引导应用程序时只将其作为快速烟雾测试使用。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42683150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档