`
liugang594
  • 浏览: 987506 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用JDI监听Java程序运行

 
阅读更多

Java虚拟机提供了一套用于调试(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去监视程序的运行的。

 

首先假设有一个简单的程序:

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的定义:

JDI - Java Debug Interface 
Defines a high-level Java language interface which tool developers can easily use to write remote debugger applications. 

 

所以首先,我们先以远程调试的方式启动上面的Test类:

java -Xdebug -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8800 -cp . test.Test

 

大致就是以socket传输的方式调试Test类,调试的连接端口为8800,并且连接过程不挂起。

 

一量启动,就可以看到如下的输出:

 

Listening for transport dt_socket at address: 8800
hello
hello
hello

 

这样Server被调试端就准备好了,下面就是写监听端了。这里就要用到jdk中提供的JDI接口了。要使用此接口,我们需要在类路径里包含JDK下的tools.jar等包,可以在<JDK>/lib目录下找着。

一、取得连接器

		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 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);

 

三、取得要关注的类和方法

		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();
		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()的实现

	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();
		}
	}

 

最后看输出:

[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

 

 

分享到:
评论
2 楼 u010221220 2016-05-19  
请问楼主一二三部分的代码都应该放在哪个函数体中。
1 楼 luly0630 2013-05-19  
GOOD!

相关推荐

    使用 Eclipse 远程调试 Java 应用程序

    本篇文章将深入探讨如何使用Eclipse进行远程调试Java应用程序。 首先,确保你已经安装了Eclipse的最新版本,例如Ganymede(V3.4)。Ganymede引入了套接字监听连接器,使得远程调试变得更加灵活。在创建启动配置时,...

    JAVAECLIPSE下配置WINDCHILL远程调试WINDCHILL学习笔记.pdf

    远程调试是指在一个主机上调试运行在另一台机器上的应用程序的技术。这对于分布式系统的开发尤其有用,因为它允许开发者在不同的环境中调试代码,确保应用能够正确地在目标环境中运行。 #### 二、配置步骤 ##### 1...

    JPDA文章汇总

    综上所述,JPDA是Java开发中不可或缺的调试框架,通过深入学习其原理和实践,开发者可以更好地理解和控制Java应用程序的运行,提升问题排查和优化的能力。在提供的博客链接中,你可以找到更多关于JPDA的实战经验和...

    java 远程调试一个朋友推荐

    2. **效率提升**:无需反复打包、部署即可实时查看程序运行状态,极大提高了开发效率。 3. **问题快速定位**:特别是在微服务架构下,远程调试可以帮助开发人员快速定位故障服务,减少故障排查时间。 4. **团队协作*...

    施懿民:生产环境下的Java排错调优

    JPDA提供了一套标准接口,使得调试工具能够与正在运行的Java应用程序交互。该架构主要由以下几个部分组成: - **Java虚拟机工具接口 (JVMTI)**:提供了对虚拟机内部操作的低级别访问,包括线程状态、类加载等。 - *...

    基于java的文本编辑实现

    这需要与Java的调试接口(如JDI - Java Debug Interface)交互,允许开发者在运行时检查程序状态,这对于学习和优化代码非常有用。 6. **文件操作** 文本编辑器还需要支持打开、保存和另存为文件的功能。这涉及...

    一个jsp的eclipse开发

    5. **JDI**:调试客户端使用的一组 Java 接口。 #### 三、JVM 调试参数详解 为了以调试模式启动 JVM,可以使用以下参数: - `-Xdebug`:启用调试支持。 - `-Xnoagent`:不使用默认的代理。 - `-Xrunjdwp:...

    如何debug你的Polish程序

    Polish是一种用于创建J2ME(Java 2 Micro Edition)应用的开发工具包,它提供了高级的编程接口和优化机制,使得开发者能够编写出运行速度快、内存占用小的应用程序。由于其特殊的编译和运行机制,在调试过程中会遇到...

    jdk 参数详解

    JDK参数详解:在Java开发中,理解并正确使用JDK参数对于优化应用程序性能、排查问题至关重要。本文将重点讲解如何利用JDK的JPDA(Java Platform Debugger Architecture)接口来解决特定问题,特别是如何在Weblogic...

    debug-changebreakpoint.rar_Windows编程_Java_

    本压缩包"debug-changebreakpoint.rar"涉及的核心知识点是调试(debug)和断点(breakpoint)管理,这对于理解和优化Java程序的运行至关重要。我们将深入探讨这两个概念,并结合提供的"debug-changebreakpoint.js"文件...

    eclipse给jar包打断点

    Eclipse的调试功能依赖于Java Debug Interface (JDI),它是Java Development Kit (JDK)的一部分。确保你已经安装了最新版本的JDK,并且Eclipse也配置了正确的JDK路径。 步骤1:导入jar包到Eclipse 要调试jar包中的...

    IDEA实现远程调试步骤详解

    远程调试使得开发者可以在本地IDEA环境中调试运行在远程服务器上的应用程序,这对于分布式系统或者大型项目的开发尤其有用。下面将详细介绍IDEA实现远程调试的步骤。 **一、远程调试基本原理** 远程调试的核心在于...

Global site tag (gtag.js) - Google Analytics