Java Instrumentation for hot replacement

original
2016/05/21 22:00
Reading 2.5K

Using Instrumentation, developers can build an agent independent of applications to monitor and assist programs running on the JVM, and even replace and modify the definitions of some classes. With this feature, developers can implement more flexible runtime virtual machine monitoring and Java class operations. This feature actually provides an AOP implementation method supported at the virtual machine level, enabling developers to implement some AOP functions without any upgrade and change to the JDK.

There are many online instructions based on Instrumentation. I don't want to introduce too much. Here is a simple example based on some requirements encountered in the project.

The project is a mobile online game. The business of the game is highly changeable. Especially during the development of the project and in the early stage after the project goes online, some things change very little, but they are important for the game, such as the drop rate, or some other numerical impact. This may be the same value for the program, In this case, restarting the server is not worth the cost. It would be better if hot replacement could be carried out. Let's look at a regular check of the files that need to be changed in the specified folder, and then hot replace them.

1. First, we need to provide a class with a premain method

 package com.hotpatch; import java.lang.instrument.Instrumentation; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; /** *Hot replacement *  * @author ksfzhaohui *  */ public class HotPatch { private final static Logger logger = Logger.getLogger(HotPatch.class); public static void premain(String agentArgs, Instrumentation inst) { Executors.newScheduledThreadPool(1).scheduleAtFixedRate( new HotPatchThread(inst), 5, 5, TimeUnit.SECONDS); logger.info("hotPatch starting..."); } }

A premain method is provided, and a timer is started to execute the HotPatchThread thread regularly.

2. HotPatchThread thread

 package com.hotpatch; import java.io.File; import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; import java.util.List; import org.apache.log4j.Logger; /** *Hot Replace Thread *  * @author ksfzhaohui *  */ public class HotPatchThread implements Runnable { private final static Logger logger = Logger.getLogger(HotPatchThread.class); private static final String ROOT_PATH = "hotfiles"; private Instrumentation inst; public HotPatchThread(Instrumentation inst) { this.inst = inst; } public void run() { try { List<File> list = FileUtil.readfile(ROOT_PATH); if (list !=  null && list.size() > 0) { for (File file : list) { Class<?> clazz = Class.forName(getPackageName(file)); byte[] array = FileUtil.getBytesFromFile(file.getPath()); ClassDefinition def = new ClassDefinition(clazz, array); inst.redefineClasses(def); file.delete(); logger.info("hotpatch " + file.getPath() + " success"); } } } catch (Exception e) { logger.error("hotpatching error", e); } } /** *Get the package name+class name of the class *  * @param file * @return */ private String getPackageName(File file) { String path = file.getPath(); int index = path.indexOf(ROOT_PATH); path = path.substring(index + ROOT_PATH.length() + 1); path = path.split("\\.")[0]; path = path.replaceAll("\\\\", "."); return path; } }

The HotPatchThread thread regularly reads the files to be updated under the hotfiles path, and then performs hot replacement,
Note: The package name needs to exist in the form of a folder

Let's take a look at the code structure:

The structure is simple. It implements simple hot replacement for three classes

Source code address: https://github.com/ksfzhaohui/hotpatch.git

Here's a simple test:

 package agentTest; public class AgentTest { public static void main(String[] args) throws InterruptedException { TClass c = new TClass(); while (true) { System.out.println(c.getNumber()); Thread.sleep(1000); } } }

Read number every second

 package agentTest; public class TClass { private int k = 10; public int getNumber() { return k + 4; } }

Print the program into jar packages, such as test.jar , and then you can write a bat file: run.bat
 

 java -javaagent:hotpatch-0.0.1-SNAPSHOT.jar -cp test.jar agentTest.AgentTest

Next, modify the TClass file, change k+4 to k+5, compile it into a class file, and place it in the hotfiles folder

There is an agentTest folder (TClass package name) under the hotfiles folder, and the changed TClass. class file is below agentTest

Operation results:

Summary: In general, some simple requirements can be realized, and only the existing methods can be modified. For the structural modification of the entire class, the virtual machine still needs to be restarted

Expand to read the full text
Loading
Click to join the discussion 🔥 (10) Post and join the discussion 🔥
Reward
ten comment
six Collection
two fabulous
 Back to top
Top