一、编写被测试类Test.java。每隔5秒钟运行一次printHello()方法打印一次信息。
二、编写调试类TestDebugger.java。用来远程调试Test.java。该方法在test.Test方法第34行设置断点,并监听。当程序运行到34行时,获取堆栈中变量信息,打印出来。
三、运行被调试类Test.java。以Debug模式运行,监听8800端口。
四、运行调试类TestDebugger。
package test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class Test {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
Test test = new Test();
while (true) {
try {
sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
printHello();
}
}
}.start();
}
protected static void printHello() {
Random r = new Random();
int i = r.nextInt();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
System.out.println(date + " : " + i);
}
}
二、编写调试类TestDebugger.java。用来远程调试Test.java。该方法在test.Test方法第34行设置断点,并监听。当程序运行到34行时,获取堆栈中变量信息,打印出来。
package test;
import java.util.List;
import java.util.Map;
import com.sun.jdi.Bootstrap;
import com.sun.jdi.IntegerValue;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.MethodEntryEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.tools.jdi.SocketAttachingConnector;
public class TestDebugger {
public static final String HOST = "hostname";
public static final String PORT = "port";
static VirtualMachine vm;
static EventQueue eventQueue;
static EventRequestManager eventRequestManager;
static Process process;
static EventSet eventSet;
static boolean vmExit = false;
public static void main(String[] args) throws Exception {
// 一、取得连接器
VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
List<AttachingConnector> connectors = vmm.attachingConnectors();
SocketAttachingConnector sac = null;
for (AttachingConnector ac : connectors) {
if (ac instanceof SocketAttachingConnector) {
sac = (SocketAttachingConnector) ac;
break;
}
}
if (sac == null) {
System.out.println("JDI error");
return;
}
// 二、连接到远程虚拟器
Map<String, Connector.Argument> arguments = sac.defaultArguments();
Connector.Argument hostArg = (Connector.Argument) arguments.get(HOST);
Connector.Argument portArg = (Connector.Argument) arguments.get(PORT);
// hostArg.setValue("127.0.0.1");
portArg.setValue(String.valueOf(8800));
vm = sac.attach(arguments);
process = vm.process();
eventRequestManager = vm.eventRequestManager();
// 三、取得要关注的类和方法
List<ReferenceType> classesByName = vm.classesByName("test.Test");
if (classesByName == null || classesByName.size() == 0) {
System.out.println("No class found");
return;
}
ReferenceType rt = classesByName.get(0);
List<Method> methodsByName = rt.methodsByName("printHello");
if (methodsByName == null || methodsByName.size() == 0) {
System.out.println("No method found");
return;
}
Method method = methodsByName.get(0);
// 四、注册监听
vm.setDebugTraceMode(VirtualMachine.TRACE_EVENTS);
vm.resume();
List<Location> locations = classesByName.get(0).locationsOfLine(34);
BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(locations.get(0));
breakpointRequest.enable();
// MethodEntryRequest methodEntryRequest = eventRequestManager.createMethodEntryRequest();
// methodEntryRequest.addClassFilter(rt);
// methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
// // methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
//
// methodEntryRequest.enable();
//
// BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(method.location());
// breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
// // breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
// breakpointRequest.enable();
// ClassPrepareRequest classPrepareRequest = eventRequestManager.createClassPrepareRequest();
// classPrepareRequest.addClassFilter("test.Test");
// classPrepareRequest.addCountFilter(1);
// classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
// classPrepareRequest.enable();
eventLoop();
}
private static void eventLoop() throws Exception {
eventQueue = vm.eventQueue();
while (true) {
if (vmExit == true) {
break;
}
eventSet = eventQueue.remove();
EventIterator eventIterator = eventSet.eventIterator();
while (eventIterator.hasNext()) {
Event event = (Event) eventIterator.next();
execute(event);
}
}
}
private static void execute(Event event) throws Exception {
if (event instanceof VMStartEvent) {
System.out.println("VM started");
eventSet.resume();
} else if (event instanceof BreakpointEvent) {
System.out.println("Reach Method printHello of test.Test");
BreakpointEvent breakpointEvent = (BreakpointEvent) event;
ThreadReference threadReference = breakpointEvent.thread();
StackFrame stackFrame = threadReference.frame(0);
stackFrame.visibleVariables();
// 获取date变量
LocalVariable localVariable = stackFrame.visibleVariableByName("date");
Value value = stackFrame.getValue(localVariable);
String date = ((StringReference) value).value();
LocalVariable localVariable1 = stackFrame.visibleVariableByName("i");
Value value1 = stackFrame.getValue(localVariable1);
int i = ((IntegerValue) value1).intValue();
System.out.println("Debugger print[" + date + " : " + i + "]");
eventSet.resume();
} else if (event instanceof MethodEntryEvent) {
MethodEntryEvent mee = (MethodEntryEvent) event;
Method method = mee.method();
System.out.println(method.name() + " was Entered!");
eventSet.resume();
} else if (event instanceof VMDisconnectEvent) {
vmExit = true;
} else if (event instanceof ClassPrepareEvent) {
ClassPrepareEvent classPrepareEvent = (ClassPrepareEvent) event;
String mainClassName = classPrepareEvent.referenceType().name();
if (mainClassName.equals("test.Test")) {
System.out.println("Class " + mainClassName + " is already prepared");
}
if (true) {
// Get location
ReferenceType referenceType = classPrepareEvent.referenceType();
List locations = referenceType.locationsOfLine(34);
Location location = (Location) locations.get(0);
// Create BreakpointEvent
BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(location);
breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
breakpointRequest.enable();
}
eventSet.resume();
} else {
eventSet.resume();
}
}
}
三、运行被调试类Test.java。以Debug模式运行,监听8800端口。
D:\workspace\Jdi\bin>java -Xdebug -agentlib:jdwp=transport=dt_socket,serve
r=y,suspend=y,address=8800 -cp . test.Test
四、运行调试类TestDebugger。