简体   繁体   English

字节码操作/增强和 Java Instrumentation API

[英]Bytecode manipulation/enhancement and Java Instrumentation API

I'm having a hard time to wrap my head around the dependency between Bytecode manipulation/enhancement and Java Instrumentation API.我很难理解字节码操作/增强和 Java Instrumentation API 之间的依赖关系。

Based on my understanding to do any bytecode manipulation/enhancement we have two options根据我对执行任何字节码操作/增强的理解,我们有两种选择

  • Build-time - Java classes were compiled to *.class then some other library/application should be executed to do the manipulation.构建时 - Java 类被编译为*.class然后应该执行一些其他库/应用程序来进行操作。
  • Load-time - Only by making use of the Java Instrumentation API, which means a particular javaagent must be provided.加载时间 - 仅通过使用 Java Instrumentation API,这意味着必须提供特定的 javaagent。

The things I'm not sure about:我不确定的事情:

  • Is there such thing as build-time bytecode manipulation and what are some frameworks/libs which support that (eg Javassist, ASM) Do they use some common approach or just reading and parsing the bytecode and then provide you a way to modify it?是否有诸如构建时字节码操作之类的东西,哪些框架/库支持该操作(例如 Javassist、ASM),它们是使用一些通用方法还是仅读取和解析字节码,然后为您提供修改它的方法?

  • Does load-time manipulation rely only on the Java Instrumentation API?加载时操作是否仅依赖于 Java Instrumentation API? Meaning all the available frameworks/libs (eg Javassist, ASM) use javaagent to do the manipulation?意思是所有可用的框架/库(例如 Javassist、ASM)都使用 javaagent 来进行操作?

Please note that I have a very small experience with this topic, so there is a chance I misunderstood or missed some concepts.请注意,我对这个主题的经验非常少,所以我有可能误解或遗漏了一些概念。 I'm trying to boil down this complex topic to some simple explanation even if it will be very general or demonstrated using an analogy.我试图将这个复杂的主题归结为一些简单的解释,即使它非常笼统或使用类比来演示。

Think of a compiled Java class file as a byte[] array that contains any information of a specific Java class.将编译后的 Java 类文件视为包含特定 Java 类的任何信息的byte[]数组。 Instrumentation in this context refers to the process of post-processing this byte array into a different shape, independently of when or how this happens.在此上下文中,检测是指将此字节数组后处理为不同形状的过程,与何时或如何发生无关。 Instrumentation can be applied during any time between compilation and class loading;可以在编译和类加载之间的任何时间应用检测; in Java, a class can even be instrumented after it has been loaded with the limitation of not changing its shape, ie adding/removing fields or methods.在 Java 中,一个类甚至可以在加载后进行检测,但不能改变其形状,即添加/删除字段或方法。 But no matter when instrumentation is applied, the concept remains the same, ie rearranging a byte array that represents a compiled Java class.但是无论何时应用检测,概念都保持不变,即重新排列表示已编译 Java 类的字节数组。

Any byte code manipulation library that I am aware of, allows to process class files from any source.我知道的任何字节码操作库都允许处理来自任何来源的类文件。 Typically, the most generic input to these libraries is a simple byte array which can optionally be loaded from a class loader for convenience.通常,这些库的最通用输入是一个简单的字节数组,为了方便,可以选择从类加载器加载它。 A class file can be looked up from a class loader via the ClassLoader.getResourceAsStream method with the name of the class file as argument.可以通过ClassLoader.getResourceAsStream方法从类加载器中查找类文件,并将类文件的名称作为参数。 For example:例如:

classLoader.getResourceAsStream("some/Sample.class")

should resolve the class file for an imaginary some.Sample class.应该为虚构的some.Sample类解析类文件。 This typically works as class files (the byte array) needs to be located by the class loader for loading the class when it is requested for the first time.这通常是因为类文件(字节数组)需要由类加载器定位以在第一次请求时加载类。

During build-time, class files are normally located in a specific folder, eg in the target/classes folder of a Maven build.在构建时,类文件通常位于特定文件夹中,例如在 Maven 构建的target/classes文件夹中。 To instrument those classes, you only need to find those files, read them into a byte array, and then write back the changed result.要检测这些类,您只需找到这些文件,将它们读入字节数组,然后写回更改后的结果。 You can do this for example by writing your own Maven plugin in which you could for example use ASM to adjust the files.例如,您可以通过编写自己的 Maven 插件来做到这一点,例如,您可以在其中使用 ASM 来调整文件。 For convenience, you can however also use a more high-level library such as Byte Buddy's Maven plugin into which you can load your own plugin and avoid the Maven plugin API and even byte code APIs entirely.为方便起见,您也可以使用更高级的库,例如Byte Buddy 的 Maven 插件,您可以在其中加载自己的插件,并完全避免 Maven 插件 API 甚至字节码 API。 (For information, I am the author of Byte Buddy.) (有关信息,我是 Byte Buddy 的作者。)

During runtime, you could do a very similar same thing, ie locate class files that are located in some folder or jar file, find these classes and adjust them before they are loaded by the application.在运行时,您可以执行非常相似的操作,即定位位于某个文件夹或jar文件中的类文件,找到这些类并在应用程序加载它们之前对其进行调整。 This would however not always work well since jar files might also be used by other applications that would also be affected.然而,这并不总是有效,因为 jar 文件也可能被其他也会受到影响的应用程序使用。 Additionally, it would require your user to explicitly activate this instrumentation from their application.此外,它会要求您的用户从他们的应用程序中明确激活此检测。 Therefore, class file instrumentation is often applied using a Java agent what gives access to the Instrumentation API what makes this much more convenient.因此,类文件的仪器使用Java代理是什么赋予了访问常用于Instrumentation API是什么使这个方便多了。 The API allows to install a hook into Java's internal class loading mechanism which makes it possible to adjust a class's byte array right before it is loaded: API 允许在 Java 的内部类加载机制中安装一个钩子,这使得可以在加载之前调整类的字节数组:

instrumentation.addClassFileTransformer(
  (Module module, ClassLoader loader, String name, 
   Class<?> classIfLoaded, ProtectionDomain pd, byte[] classFile) -> {
     byte[] transformed = doSomethingWith(classFile);
     return transformed;
});

This change is then isolated to the application and does not change the original class files.此更改随后与应用程序隔离,并且不会更改原始类文件。 The instrumentation API does not imply the use of any library to modify a class file, this is fully up to you and everybody is using a library of some sort or even to manipulate the byte array directly.检测 API 并不意味着使用任何库来修改类文件,这完全取决于您,每个人都在使用某种库,甚至直接操作字节数组。 A high-level library such as Byte Buddy does not even require you to implement your own class file transformer but has it's own abstraction via the AgentBuilder API which does however create a class file transformer under the covers to make use of the instrumentation API's unique capabilities.像 Byte Buddy 这样的高级库甚至不需要您实现自己的类文件转换器,而是通过AgentBuilder API 拥有自己的抽象,但它会在AgentBuilder创建类文件转换器以利用检测 API 的独特功能. Other libraries such as ASM or Javassist have no relationship to the Instrumentation API however and would require you to implement your own class file transformer in which you use the APIs of those libraries to process the presented class file.但是,其他库(例如 ASM 或 Javassist)与Instrumentation API 没有关系,并且需要您实现自己的类文件转换器,在其中使用这些库的 API 来处理呈现的类文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM