java agent + Instrumentation热更新class

80 阅读1分钟

思路:为每一台应用启动一个AttachApplication服务,当指定包路径下的字节码文件有变更时,通过Instrumentation重新加载字节码文件到虚拟机,实现不停机秒级更新应用。(只能修改方法体,不支持新增方法和变量)

image.png

核心代码:

try {
    Class<?> clazz = Class.forName(className);
    ClassDefinition classDefinition = new ClassDefinition(clazz, classBytes);
    instrumentation.redefineClasses(classDefinition);
    System.out.println("Class " + className + " has been redefined.");
} catch (ClassNotFoundException e) {
    System.err.println("Class " + className + " not found: " + e.getMessage());
} catch (Exception e) {
    System.err.println("Failed to redefine class " + className + ": " + e.getMessage());
}

加载agentjar包发送到虚拟机:

try {
    List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list();

    for (VirtualMachineDescriptor vmd : vmDescriptors) {
        if (vmd.displayName().equals("Application")) { // 修改成指定的应用名称
            VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());

            // 加载 agent
            String agentPath = Paths.get("build", "libs", "java-agent.jar").toAbsolutePath().toString();
            virtualMachine.loadAgent(agentPath);

            virtualMachine.detach();
        }
    }
} catch (Exception e) {
    throw new RuntimeException();
}