bytecode - 在没有代理的情况下检测 Java 字节码
问题描述
是否可以在没有 Java 代理的情况下动态检测 Java 字节码?我之前使用 Java 代理对字节码进行了检测,做了类似的事情:
ClassFileTransformer myTransformer = new Transformer();
instrument.addTransformer(myTransformer, true);
instrument.retransformClasses(classInstance);
instrument.removeTransformer(myTransformer);
但是,如果不使用 Java 代理,这可能吗?我想做的是调用一个方法,该方法将在 JVM 运行后的任何给定时间执行我的检测,而无需使用代理。
解决方案
在没有实现实例的情况下执行字节码转换的唯一方法Instrumentation
是
可以在调用之前更改字节的自定义类加载器
defineClass
(仅限于通过该加载器加载的类)甚至在加载类之前就使用修改后的字节进行调用
MethodHandles.Lookup.defineClass
,这适用于具有延迟加载的广泛 JVM,但仅限于您自己的模块或向您的模块打开的模块
这两种方法都不能改变已经加载的类。这需要Instrumentation
引用,并且 JVM 发出此类引用的唯一地方是 Java 代理的初始化方法。因此,要使用它,Java 代理是不可避免的,即使它可能只是一个存储引用的存根,供您的应用程序代码使用。
请注意,从 Java 9 开始,Launcher-Agent-Class
jar 文件的 manifest 属性可以指定 Java 代理的类在启动指定的类之前Main-Class
启动。这样,您可以轻松地让您的代理与您的 JVM 中的应用程序代码协作,而无需任何额外的命令行选项。代理可以简单到agentmain
在主类中有一个方法,将Instrumentation
引用存储在静态变量中。
请java.lang.instrument
参阅软件包文档……</p>
Instrumentation
当 JVM 还没有通过 Agents 启动时,获取实例会比较棘手。通常,它必须支持在启动后启动代理,例如通过 Attach API。这个答案在其结尾展示了这样一种自我连接来获得Instrumentation
. 当您的应用程序 jar 文件中有必要的清单属性时,您甚至可以将其用作代理 jar 并省略临时存根文件的创建。
但是,最近的 JVM 禁止自连接,除非-Djdk.attach.allowAttachSelf=true
在启动时指定,但我想,在启动时采取额外的步骤,正是你不想做的。避免这种情况的一种方法是使用另一个过程。所有这个过程所要做的就是附加到您的原始进程并告诉 JVM 启动代理。然后,它可能已经终止,其他一切的工作方式与引入此限制之前的方式相同。
如本评论所述,Byte-Buddy 已经实现了这些必要的步骤,并且精简后的 Byte-Buddy-Agent 仅包含该逻辑,因此您可以使用它在其上构建自己的逻辑。
推荐阅读
- amazon-web-services - AWS 虚拟私有云:私有子网和 IP 范围
- java - 将所有相同的类别归入一个总数量的类别
- moodle - Moodle课程注册
- c++ - Visual Studio 2019 拒绝“bool concept”,而 gcc 8 不编译没有“bool”的概念
- python - 在 tkinter 中按下按钮后如何获得哔声?
- python-3.x - 调整轴长度
- python - Python 多处理 pool.close 和 pool.join TypeError:“NoneType”对象不可调用
- firebase - 如何使用 dart 在 Flutter 中迭代小部件
- angular - 在 Ionic 应用程序中实施 Google 地图时如何解决未定义的 google.maps.mapTypeId.ROADMAP 问题?
- python - 由于“导入包错误”,无法将数据从 pandas 数据帧上传到 AWS athena 表