使用JDI监听Java程序运行
2013-01-30 11:32
218 查看
va虚拟机提供了一套用于调试(JVMDI)和监视(JVMPI)的接口,Java5之后统一为JVMTI: http://docs.oracle.com/javase/1.5.0/docs/guide/jvmti/ 。
其中JVMDI分为三个部分:JVMDI,JDWP和JDI . http://docs.oracle.com/javase/1.4.2/docs/guide/jpda/architecture.html
这篇就是简单的介绍一下怎么使用JDI去监视程序的运行的。
首先假设有一个简单的程序:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
package test;
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();
}
test.printHello();
}
}
}.start();
}
protected void printHello() {
System.out.println("hello");
}
}
程序中,每隔五秒种,printHello()方法就会执行一次。
如果你希望每次printHell()被执行的时候通知你一下,在不修改代码的情况下,你要怎么办?没办法吧?
看看JDI的定义:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
JDI - Java Debug Interface
Defines a high-level Java language interface which tool developers can easily use to write remote debugger applications.
所以首先,我们先以远程调试的方式启动上面的Test类:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
java -Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8800 -cp . test.Test
大致就是以socket传输的方式调试Test类,调试的连接端口为8800,并且连接过程不挂起。
一量启动,就可以看到如下的输出:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
Listening for transport dt_socket at address: 8800
hello
hello
hello
这样Server被调试端就准备好了,下面就是写监听端了。这里就要用到jdk中提供的JDI接口了。要使用此接口,我们需要在类路径里包含JDK下的tools.jar等包,可以在<JDK>/lib目录下找着。
![](http://liugang594.iteye.com/images/icon_star.png)
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;
}
![](http://liugang594.iteye.com/images/icon_star.png)
Map 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);
![](http://liugang594.iteye.com/images/icon_star.png)
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);
![](http://liugang594.iteye.com/images/icon_star.png)
vm.setDebugTraceMode(VirtualMachine.TRACE_EVENTS);
vm.resume();
EventRequestManager erm = vm.eventRequestManager();
MethodEntryRequest methodEntryRequest = erm.createMethodEntryRequest();
methodEntryRequest.addClassFilter(rt);
methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
methodEntryRequest.enable();
BreakpointRequest breakpointRequest = erm
.createBreakpointRequest(method.location());
breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
breakpointRequest.enable();
eventLoop();
这里监听每次方法入口的时候,以及在方法上注册一个断点,发一个通知。
![](http://liugang594.iteye.com/images/icon_star.png)
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");
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 {
eventSet.resume();
}
}
最后看输出:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
[JDI: EventSet: SUSPEND_EVENT_THREAD]
[JDI: Event: MethodEntryEvent@test.Test:23 in thread Thread-0]
[JDI: Event: BreakpointEvent@test.Test:23 in thread Thread-0]
printHello was Entered!
Reach Method printHello of test.Test
[JDI: EventSet: SUSPEND_EVENT_THREAD]
printHello was Entered!
[JDI: Event: MethodEntryEvent@test.Test:23 in thread Thread-0]
[JDI: Event: BreakpointEvent@test.Test:23 in thread Thread-0]
Reach Method printHello of test.Test
其中JVMDI分为三个部分:JVMDI,JDWP和JDI . http://docs.oracle.com/javase/1.4.2/docs/guide/jpda/architecture.html
这篇就是简单的介绍一下怎么使用JDI去监视程序的运行的。
首先假设有一个简单的程序:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
package test;
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();
}
test.printHello();
}
}
}.start();
}
protected void printHello() {
System.out.println("hello");
}
}
程序中,每隔五秒种,printHello()方法就会执行一次。
如果你希望每次printHell()被执行的时候通知你一下,在不修改代码的情况下,你要怎么办?没办法吧?
看看JDI的定义:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
JDI - Java Debug Interface
Defines a high-level Java language interface which tool developers can easily use to write remote debugger applications.
所以首先,我们先以远程调试的方式启动上面的Test类:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
java -Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8800 -cp . test.Test
大致就是以socket传输的方式调试Test类,调试的连接端口为8800,并且连接过程不挂起。
一量启动,就可以看到如下的输出:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
Listening for transport dt_socket at address: 8800
hello
hello
hello
这样Server被调试端就准备好了,下面就是写监听端了。这里就要用到jdk中提供的JDI接口了。要使用此接口,我们需要在类路径里包含JDK下的tools.jar等包,可以在<JDK>/lib目录下找着。
一、取得连接器
Java代码![](http://liugang594.iteye.com/images/icon_star.png)
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;
}
二、连接到远程虚拟器
Java代码![](http://liugang594.iteye.com/images/icon_star.png)
Map 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);
三、取得要关注的类和方法
Java代码![](http://liugang594.iteye.com/images/icon_star.png)
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);
四、注册监听
Java代码![](http://liugang594.iteye.com/images/icon_star.png)
vm.setDebugTraceMode(VirtualMachine.TRACE_EVENTS);
vm.resume();
EventRequestManager erm = vm.eventRequestManager();
MethodEntryRequest methodEntryRequest = erm.createMethodEntryRequest();
methodEntryRequest.addClassFilter(rt);
methodEntryRequest.setSuspendPolicy(EventRequest.SUSPEND_NONE);
methodEntryRequest.enable();
BreakpointRequest breakpointRequest = erm
.createBreakpointRequest(method.location());
breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
breakpointRequest.enable();
eventLoop();
这里监听每次方法入口的时候,以及在方法上注册一个断点,发一个通知。
四、eventLoop()的实现
Java代码![](http://liugang594.iteye.com/images/icon_star.png)
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");
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 {
eventSet.resume();
}
}
最后看输出:
Java代码
![](http://liugang594.iteye.com/images/icon_star.png)
[JDI: EventSet: SUSPEND_EVENT_THREAD]
[JDI: Event: MethodEntryEvent@test.Test:23 in thread Thread-0]
[JDI: Event: BreakpointEvent@test.Test:23 in thread Thread-0]
printHello was Entered!
Reach Method printHello of test.Test
[JDI: EventSet: SUSPEND_EVENT_THREAD]
printHello was Entered!
[JDI: Event: MethodEntryEvent@test.Test:23 in thread Thread-0]
[JDI: Event: BreakpointEvent@test.Test:23 in thread Thread-0]
Reach Method printHello of test.Test
相关文章推荐
- 使用JDI监听Java程序运行
- Java使用java命令运行程序出现:找不到主类错误
- 使用脚本引擎增加程序运行时动态执行能力(Java篇)
- oracle 使用database control 配置数据库时,要求在当前oracle主目录中配置监听程序,必须运行Netca以配置
- 如何使用Eclipse编写运行Java程序
- jConsole,jvisualvm和jmap使用------观察java程序的运行,用于排错调优
- 让Java程序作为linux的Daemon后台运行 和 使用Java Service Wrapper将java程序作为linux服务并且开机自动启动
- Eclipse下使用JRat分析Java程序运行性能
- 使用Sublime Text 3 编译并运行Java程序
- 使用database control 配置数据库时,要求在当前oracle主目录中配置监听程序,必须运行Netca以配置监听程序,然后才能继续。或者可以选择继续,但是不要使用database cont
- linux使用 java -jar来运行java非web程序
- Java中使用Runtime和Process类运行外部程序
- 使用命令行运行Java程序
- Java_31_面向对象_Java程序运行的内存分析_栈_堆_引用类型的概念_属性_对象的创建和使用
- Java中使用Runtime和Process类运行外部程序
- [转]Java中使用Runtime和Process类运行外部程序
- 使用gradle编译和运行Java程序
- 【Java】使用记事本运行第一个Java程序
- 使用Daemon将java程序运行为后台service
- 通过命令行指定 Java 程序运行时使用的字符集