在运行时替换一些方法的内容 [英] Replace content of some methods at runtime

查看:22
本文介绍了在运行时替换一些方法的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在运行时替换一些方法的内容.

I would like to replace the content of some methods at runtime.

我知道我可以使用 javassist 来做这件事,但它不起作用,因为我想增强的类已经被系统 classLoader 加载了.

I know I can use javassist for this but it does not work because the classes I would like to enhance are already loaded by the system classLoader.

如何在运行时替换方法的内容?我应该尝试卸载课程吗?我怎样才能做到这一点 ?我看到这是可能的,但我不知道如何去做.

How can I do, to replace the content of a method at runtime ? Should I try to unload the class ? How can I do that ? I saw it was possible but I could not figure out how to do it.

如果可能,我想避免为此使用外部库,我想自己编写代码.

If possible, I would like to avoid using an external lib for this, I would like to code it my-self.

更多信息:- 我想增强的类包含在一个框架中(在一个 jar 文件中)- 我的代码实际上是这个框架的插件- 我的插件运行的框架有它自己的 classLoader,但是这个 classLoader 不加载它自己的类(它将它们委托给系统类加载器)- 我使用的框架是Play.

More information: - The class I would like to enhance is contained in a framework (in a jar file) - My code is actually a plugin of this framework - The framework in which my plugin runs has its own classLoader, but this classLoader does not load its own classes (it delegates them to the system class loader) - The framework I'm using is Play.

感谢您的帮助!

推荐答案

可以使用 Javaassist 以及任何其他字节码工程库来实现.神奇之处在于 Java 附加 API,它允许程序附加到正在运行的 JVM(并修改加载的类).

You can do it with Javaassist, as well as any other bytecode engineering library out there. The magic lies in the Java Attach API, which allows programs to attach to running JVMs (and modify loaded classes).

可以在com.sun.tools.attach 包,顾名思义,专用于 Oracle JVM.尽管如此,像 jstackjmap 这样的 JDK 工具使用它来支持他们的附加到运行的 JVM"功能,所以可以肯定地说它会继续存在.

It can be found in the com.sun.tools.attach package, and as the name implies, is specific to the Oracle JVM. Nonetheless, JDK tools like jstack and jmap use it to support their "attach to running JVM" feature, so it's safe to say it's here to stay.

Attach API 上的文档具有相当的描述性,这篇 Oracle 博客文章演示在运行时附加代理.一般来说,它归结为:

The docs on the Attach API are fairly descriptive, and this Oracle blog post demonstrates attaching an agent at runtime. In general, it boils down to:

  • 使用 premain
  • 以常规"-javaagent 方式重新转换程序
  • premain重命名为agentmain
  • 创建一个包含您的代理类的临时 JAR 文件,并具有一个将 Agent-Class 指向您的代理(agentmain-包含)类的清单,并且 Can-Retransform-Classes 设置为 true
  • 获取目标 JVM 的 PID(可能是同一个进程),并将临时 jar 附加到其上
  • Make a retransforming program the "regular" -javaagent way, with premain et al
  • Rename premain to agentmain
  • Create a temporary JAR file containing your agent classes and having a manifest pointing Agent-Class to your agent (agentmain-containing) class, and Can-Retransform-Classes set to true
  • Obtain the PID of the target JVM (potentially the same process), and attach the temporary jar to it

幸运的是,API 无需您做太多工作即可完成此操作,但如果您在运行时生成 JAR,则打包代理所需的所有类可能会有点棘手.

Thankfully, the API can do this without much work on your part, though if you are doing the JAR generation at runtime it may be a bit tricky to package all the classes needed by your agent.

我希望包含一个演示代理,演示在运行时附加分析器,但结果太长而无法发布.尽管如此,我还是把它放在了 Github repo 中.

I was hoping to include a demo agent demonstrating attaching a profiler at runtime, but it ended up being too lengthy to post. Nonetheless, I've put it up in a Github repo.

一个警告是这种方法使您的程序依赖于 JDK 附带的 tools.jar,而 JRE 中不存在该 tools.jar.您可以通过将 tools.jar 与(或提取到)您的应用程序一起发送来解决此问题,但您仍然需要提供 Attach API 所需的 attach 本机库你的申请.我已经在上面链接的存储库中包含了我可以找到的所有平台的库,尽管您也可以自己获取它们.

A caveat of this approach is that it makes your program dependent on the tools.jar that ships with JDKs, and which is not present in JREs. You can get around this by shipping tools.jar with (or extracted in) your application, but you will still need to provide the attach native library required by the Attach API with your application. I've included the libraries for all platforms I could find in the repository linked above, though you may obtain them by yourself too.

根据您的用例,这可能是也可能不是理想的.但它确实有效!

Depending on your usecase, this may or may not be ideal. But it certainly works!

这在问题中并不清楚,但是如果您希望在运行时完全热交换"一个类与您自己的类,则不需要使用任何字节码操作库.相反,您可以单独编译您的类(确保相同的包、类名等)并在您的目标上调用 transform 时简单地返回新类的字节班级.

This isn't clear in the question, but if what you wish to do is completely "hotswap" a class at runtime with your own, you do not need to use any bytecode manipulation library. Instead, you may compile your class separately (ensuring the same package, class name, etc.) and simply return the bytes for your new class when transform is called on your target class.

这篇关于在运行时替换一些方法的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆