Java:在运行时从同一 JVM 中获取类的字节码

发布于 2024-10-01 10:57:43 字数 472 浏览 0 评论 0原文

相关于: 是有没有办法在运行时获取类的字节码?

我正在为 Clojure 添加持久性,我终于准备好添加函数了。在 Clojure 中,函数被字节编译成带有调用方法(等等)的类。这样,功能是一流的。为了使这些类持久,我需要序列化和反序列化这些类。如何在无法访问 .class 文件的情况下获取类的字节码?

如果我弄错了,请纠正我,但使用代理需要生成一个单独的虚拟机,并将代理连接到第一个虚拟机。我需要从同一个虚拟机执行此操作。

仅使用 Serialized 来设置和获取 Class 对象是不够的。反序列化时,我需要加载该类,并且在后续的 VM 实例中,可能会出现类名冲突。我需要修改字节码以在反序列化/类加载时将类重命名为唯一的名称。

Related to: Is there a way to obtain the bytecode for a class at runtime?

I'm adding durability to Clojure, and I'm finally at the point where I'm ready to add functions. In Clojure, functions are byte compiled into classes with invoke methods (among others). In this way, functions are first class. To make these durable, I need to serialize and deserialize these classes. How do I get the bytecode for the class without having access to the .class file?

Please correct me if I'm mistaken, but using an agent requires spawning a separate VM with the agent connecting to the first VM. I need to do it from the same VM.

It's not enough to use Serializable to set and get the Class object. Upon deserializing, I need to load the class, and upon subsequent VM instances, there may be a class name collision. I need to modify the bytecode to rename the class to something unique at deserialization/class-load time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

仲春光 2024-10-08 10:57:43

您可以编写自己的 ClassLoader 并编写一个方案,在加载类时记录字节码。

您需要重写findClass来自己查找类文件,将其加载到内存中,将数据保存在某处(以供以后序列化),然后调用defineClass来定义该类JVM。

You could write your own ClassLoader and hack up a scheme which records the bytecode as classes are loaded.

You would need to override findClass to find the class file yourself, load it into memory, save the data somewhere (for later serialization), then call defineClass to define that class in the JVM.

携君以终年 2024-10-08 10:57:43

除非您通过棘手的类加载器运行代码,否则您应该能够执行以下操作:

Class<?> clazz = ....
String className = clazz.getCanonicalName();  // e.g. "foo.Bar"
String resourceName = ... // map className to a resource name; e.g. "/foo/Bar.class" 
InputStream is = clazz.getClassLoader().getResourceAsStream(resourceName);

这为您提供了“.class”文件内容的句柄......如果可以找到它。

注意事项。某些类加载器可能:

  • 根本不允许打开“.class”资源,
  • 为您提供加密的字节码流,或者
  • 由于类加载器执行的某些即时转换而为您提供不完全是正在运行的字节码。

如果这种方法不起作用,那么您几乎别无选择,因为 JVM 不提供访问已加载的实际字节码的方法。

Unless you are running code via a tricky classloader, you should be able to do something like this:

Class<?> clazz = ....
String className = clazz.getCanonicalName();  // e.g. "foo.Bar"
String resourceName = ... // map className to a resource name; e.g. "/foo/Bar.class" 
InputStream is = clazz.getClassLoader().getResourceAsStream(resourceName);

This gives you a handle on the contents of the ".class" file ... if it can be found.

Caveats. Some classloaders might:

  • not let to open the ".class" resources at all,
  • give you an encrypted bytecode stream, or
  • give you bytecodes that are nor exactly what is being run, due to some on-the-fly transformation performed by the classloader.

If this approach doesn't work, you are pretty much out of options because the JVM does not provide a way to access the actual bytecodes that were loaded.

时间你老了 2024-10-08 10:57:43

您还可以使用 Java Instrumentation API 来实现此目的。在调用defineClass 之前,您可以访问类文件的字节。你也可以改变它们!

You can also use the Java Instrumentation API for this. You get access to the bytes of the classfile before defineClass is invoked. You can change them too!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文