总的来说,JDK端的代码,目的就是:
- 给JVM发送SIGBREAK信号,触发Attach Listener线程的创建;
- 给JVM发送load命令,让JVM执行加载目标agent的操作;
- 接收JVM返回的执行结果,判断是否加载agent成功;
流程图:
我们在外部程序里只需要两行编码:
VirtualMachine virtualMachine = VirtualMachine.attach(String.valueOf(pid));
virtualMachine.loadAgent("agent.jar=args");
- attach方法
public static VirtualMachine attach(String id)
throws AttachNotSupportedException, IOException
{
if (id == null) {
throw new NullPointerException("id cannot be null");
}
List<AttachProvider> providers = AttachProvider.providers();
if (providers.size() == 0) {
throw new AttachNotSupportedException("no providers installed");
}
AttachNotSupportedException lastExc = null;
for (AttachProvider provider: providers) {
try {
return provider.attachVirtualMachine(id);
} catch (AttachNotSupportedException x) {
lastExc = x;
}
}
throw lastExc;
}
此方法通过AttachProvider.providers()得到所有的provider,并逐个调用它们的attachVirtualMachine方法,只要有一个成功就返回。
provider.attachVirtualMachine是个抽象方法,以Linux中的实现为例:
public VirtualMachine attachVirtualMachine(String vmid)
throws AttachNotSupportedException, IOException
{
checkAttachPermission();
// AttachNotSupportedException will be thrown if the target VM can be determined
// to be not attachable.
testAttachable(vmid);
return new LinuxVirtualMachine(this, vmid);
}
/**
* Attaches to the target VM
*/
LinuxVirtualMachine(AttachProvider provider, String vmid)
throws AttachNotSupportedException, IOException
{
super(provider, vmid);
// This provider only understands pids
int pid;
try {
pid = Integer.parseInt(vmid);
} catch (NumberFormatException x) {
throw new