Java Attach API的作用是什么?

  • Post category:Java

Java Attach API是Java SE 6及以上版本中提供的一组API,其作用是允许在运行中的Java虚拟机中注入代码或从已经运行的Java虚拟机中获取信息。其主要用于与Java虚拟机进行连接和信息交互的场景,比如:调试、性能监控和诊断分析等。

完整使用攻略:

  1. 下载tools.jar

Java Attach API位于tools.jar中,需要从Java开发套件中提取该文件才能使用。首先下载和安装Java Development Kit (JDK),然后将tools.jar从JDK的安装目录(%JAVA_HOME%/lib/)中复制到自定义目录中,以备后用。

  1. 加载Java Attach API

Java Attach API最重要的类是VirtualMachine,它表示本地虚拟机或远程虚拟机,可以用来连接、启动和管理Java虚拟机。为了加载VirtualMachine类,需要把tools.jar中的对应类文件添加到classpath或直接使用它的绝对路径:

// 加载VirtualMachine类
URLClassLoader loader =
    new URLClassLoader(new URL[]{new File("tools.jar").toURI().toURL()});
Class<?> vmClass = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader);
  1. 连接Java虚拟机

连接本地虚拟机或远程虚拟机都可以使用VirtualMachine类的attach方法。attach方法会返回一个VirtualMachine对象,用于后续的交互。

// 获取本地虚拟机并连接
VirtualMachine vm = VirtualMachine.attach("pid");

pid是Java虚拟机的进程id,可以通过jps命令或Java Management Extensions(JMX)获取。

  1. 注入代码

Java Attach API通过Instrumentation接口提供了在Java虚拟机运行过程中注入JVM Agent的能力。注入的Agent可以修改字节码或者使用JVMTI实现代码植入的目的。具体来说,Instrumentation的两个重要方法是addTransformer和retransformClasses。这两个方法都需要在Agent或者premain后重新启动函数在JVM生命周期中执行,在启动时得到的所有加载类将被注册,但只有addTransformer的函数会被用于映射文件(即不改变原始字节码)。除此之外,加注入JVM Agent操作需要启动前另一个Agent操作,重写方法转换处理。

下面是一个简单的Agent,它会在启动时输出所有类的名称和版本:

public static class ClassVersioner implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, 
                            String className, 
                            Class<?> classBeingRedefined,
                            ProtectionDomain protectionDomain, 
                            byte[] classfileBuffer) throws IllegalClassFormatException {
        System.out.println("Transforming " + className);
        return classfileBuffer;
    }
}
public static void premain(String args, Instrumentation inst) {
    System.out.println("Premain " + args);
    inst.addTransformer(new ClassVersioner());
}
  1. 获取Java虚拟机信息

Java Attach API也能够用于获取Java虚拟机的信息,比如系统属性、命令行参数、线程堆栈等。通过VirtualMachine对象的getSystemProperties和getAgentProperties方法可以获取系统属性和Agent属性。

示例1:获取Java虚拟机系统属性

// 获取Java虚拟机基本信息
Properties props = vm.getSystemProperties();
for (Map.Entry<Object, Object> entry : props.entrySet()) {
    System.out.println(entry.getKey() + "=" + entry.getValue());
}

示例2:获取Java虚拟机命令行参数

// 获取Java虚拟机命令行参数
String[] args = vm.getAgentProperties().getProperty("sun.java.command").split(" ");
for (String arg : args) {
    System.out.println(arg);
}

以上就是Java Attach API的使用攻略,其涉及到了动态注入代码和获取Java虚拟机信息的场景。