


Detailed explanation of using dynamic mounting to implement bug hot fix in Java (picture)
Most JVMs have Java's HotSwap feature, and most developers think it is just a debugging tool. Using this feature, it is possible to change the implementation of Java methods without restarting the Java process. A typical example is coding using an IDE. However HotSwap can implement this functionality in a production environment. In this way, you can extend your online application or fix minor bugs in a running project without stopping the running program. In this article, I will demonstrate dynamic binding, apply runtime code changes for binding, introduce some tools API, and the Byte Buddy library, which provides some API code changes more conveniently.
Suppose there is a running application that performs special processing on the server by validating the X-Priority header in HTTP requests. This verification is implemented using the following tool class:
class HeaderUtility { static boolean isPriorityCall(HttpServletRequest request) { return request.getHeader("X-Pirority") != null; } }
Did you find the error? Such errors are common, especially when constant values are decomposed into static fields for reuse in test code. In a less-than-ideal scenario, the error would only be discovered when the product is installed, where the header is generated by another application and contains no typos.
It is not difficult to fix errors like this. In the age of continuous delivery, redeploying a new version is just a click of a button away. But in other cases, the change may not be that simple, and the redeployment process may be complex, where downtime is not allowed and running with errors may be better. But HotSwap provides us with another option: making small changes without restarting the application.
Attach API: Use dynamic attachments to penetrate another JVM
In order to modify a running Java program, we first need a method that can be in the same running state The way the JVM communicates. Because Java's virtual machine implementation is a managed system, it has a standard API for performing these operations. The API involved in the question is called the attachment API, which is part of the official Java tools. Using this API exposed by the running JVM, a second Java process can communicate with it.
In fact, we have already used this API: it has been applied by debugging and simulation tools such asVisualVM or Java Mission Control . The API for applying these attachments is not packaged with the standard Java API used daily, but is packaged into a special file called tools.jar, which only contains the JDK of a virtual machine Package the release version. What's worse is that the location of this JAR file has not been set. It is different in VMs on Windows, Linux, and especially on Macintosh. Not only the location of the file, but also the file name is different. On some distributions, it is called classes.jar. In the end, IBM even decided to change the names of some classes contained in this JAR and moved all com.sun classes to com.ibm namespace, adding another mess. In Java 9, the mess was finally cleaned up, and tools.jar was replaced by Jigsaw's module jdk.attach.
// the following strings must be provided by us String processId = processId(); String jarFileName = jarFileName(); VirtualMachine virtualMachine = VirtualMachine.attach(processId); try { virtualMachine.loadAgent(jarFileName, "World!"); } finally { virtualMachine.detach(); }After receiving a JAR file, the target virtual machine will view the JAR's program manifest description file (manifest) and locates the class under the Premain-Class attribute. This is very similar to how the VM executes a main method. With a Java agent, the VM and the specified process id can find a method named agentmain, which can be executed by the remote process in the specified thread:
public class HelloWorldAgent { public static void agentmain(String arg) { System.out.println("Hello, " + arg); } }Using this API, as long as we know With the process ID of a JVM, you can run code on it and print out a Hello, World! message. It is even possible to communicate with a JVM that is not familiar with parts of the JDK distribution, as long as the attached VM is a JDK installer that accesses tools.jar.
Instrumentation API:修改目标 VM 的程序
到目前来看一切顺利。但是除了成功地同目标 VM 建立起了通信之外,我们还不能够修改目标 VM 上的代码以及 BUG。后续的修改,Java 代理可以定义第二参数来接收一个 Instrumentation 的实例 。稍后要实现的接口提供了向几个底层方法的访问途径,它们中的一个就能够对已经加载的代码进行修改。
为了修正 “X-Pirority” 错字,我们首先来假设为 HeaderUtility 引入了一个修复类,叫做 typo.fix,就在我们下面所开发的 BugFixAgent 后面的代理的 JAR 文件中。此外,我们需要给予代理通过向 manifest 文件添加 Can-Redefine-Classes: true 来替换现有类的能力。有了现在这些东西,我们就可以使用 instrumentation 的 API 来对类进行重新定义,该 API 会接受一对已经加载的类以及用来执行类重定义的字节数组:
public class BugFixAgent { public static void agentmain(String arg, Instrumentation inst) throws Exception { // only if header utility is on the class path; otherwise, // a class can be found within any class loader by iterating // over the return value of Instrumentation::getAllLoadedClasses Class<?> headerUtility = Class.forName("HeaderUtility"); // copy the contents of typo.fix into a byte array ByteArrayOutputStream output = new ByteArrayOutputStream(); try (InputStream input = BugFixAgent.class.getResourceAsStream("/typo.fix")) { byte[] buffer = new byte[1024]; int length; while ((length = input.read(buffer)) != -1) { output.write(buffer, 0, length); } } // Apply the redefinition instrumentation.redefineClasses( new ClassDefinition(headerUtility, output.toByteArray())); } }
运行上述代码后,HeaderUtility 类会被重定义以对应其修补的版本。对 isPrivileged 的任何后续调用现在将读取正确的头信息。作为一个小的附加说明,JVM 可能会在应用类重定义时执行完全的垃圾回收,并且会对受影响的代码进行重新优化。 总之,这会导致应用程序性能的短时下降。然而,在大多数情况下,这是较之完全重启进程更好的方式。
当应用代码更改时,要确保新类定义了与它替换的类完全相同的字段、方法和修饰符。 尝试修改任何此类属性的类重定义行为都会导致 UnsupportedOperationException。现在 HotSpot 团队正试图去掉这个限制。此外,基于 OpenJDK 的动态代码演变虚拟机支持预览此功能。
使用 Byte Buddy 来追踪内存泄漏
一个如上述示例的简单的 BUG 修复代理在你熟悉了 instrumentation 的 API 的时候是比较容易实现的。只要更加深入一点,也可以在运行代理的时候,无需手动创建附加的 class 文件,而是通过重写现有的 class 来应用更多通用的代码修改。
字节码操作
编译好的 Java 代码所呈现的是一系列字节码指令。从这个角度来看,一个 Java 方法无非就是一个字节数组,其每一个字节都是在表示一个向运行时发出的指令,或者是最近一个指令的参数。每个字节对应其意义的映射在《Java 虚拟机规范》中进行了定义,例如字节 0xB1 就是在指示 VM 从一个带有 void 返回类型的方法返回。因此,对字节码进行增强就是对一个方法的字节数字进行扩展,将我们想要应用的表示额外的业务逻辑指令包含进去。
当然,逐个字节的操作会特别麻烦,而且容易出错。为了避免手工的处理,许多的库都提供了更高级一点的 API,使用它们不需要我们直接同 Java 字节码打交道。这样的库其中就有一个叫做 Byte Buddy (当然我就是该库的作者)。它的功能之一就是能够定义可以在方法原来的代码之前和之后被执行的模板方法。
The above is the detailed content of Detailed explanation of using dynamic mounting to implement bug hot fix in Java (picture). For more information, please follow other related articles on the PHP Chinese website!

The article discusses using Maven and Gradle for Java project management, build automation, and dependency resolution, comparing their approaches and optimization strategies.

The article discusses creating and using custom Java libraries (JAR files) with proper versioning and dependency management, using tools like Maven and Gradle.

The article discusses implementing multi-level caching in Java using Caffeine and Guava Cache to enhance application performance. It covers setup, integration, and performance benefits, along with configuration and eviction policy management best pra

The article discusses using JPA for object-relational mapping with advanced features like caching and lazy loading. It covers setup, entity mapping, and best practices for optimizing performance while highlighting potential pitfalls.[159 characters]

Java's classloading involves loading, linking, and initializing classes using a hierarchical system with Bootstrap, Extension, and Application classloaders. The parent delegation model ensures core classes are loaded first, affecting custom class loa


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Atom editor mac version download
The most popular open source editor

SublimeText3 Linux new version
SublimeText3 Linux latest version

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),