Atitit.获取swing ui 按钮控件的id 与名字 与JPDA 调试体系

邓英卓
2023-12-01

Atitit.获取swing ui 按钮控件的id 与名字 与JPDA 调试体系

 

1Swing Inspector是一个Java Swing/AWT用户界面分析和调试工具,功能与firebug类似,2

2类似spylite firebug3

3Eclipse  vm param3

4Cltr+f12显示主界面3

5Ctrl+鼠标找到控件3

6JPDA(Java Platform Debugger Architecture)是 Java 平台调试体系结构的缩写。4

6.1. Java 调试接口的特点4

6.2. JPDA 组成模块5

6.3. JVMTI 的简介6

6.4. Agent 的工作过程7

6.4.1. 启动7

6.5. JVMTI 基本功能7

6.5.1. 事件处理和回调函数7

6.5.2. 内存控制和对象获取8

6.5.3. 线程和锁8

6.5.4. 调试功能9

6.6. 主要部分9

6.6.1. Java 虚拟机工具接口(JVMTI)9

6.6.2. Java 调试线协议(JDWP)9

6.6.3. Java 调试接口(JDI)10

7找到源码10

 

1. Swing Inspector是一个Java Swing/AWT用户界面分析和调试工具,功能与firebug类似,

具有强大的Swing/AWT用户界面分析和调试相关功能。 适用于从java swing初级到高级的所有开发人员,能够快速定位问题,UI快速调试,分析其他软件界面的实现原理,能够给开发工作效率带来大幅提升。

特点:

1. 具备UI组件联动功能,在用户界面中Ctrl+移动鼠标(Mac OSX ⌘+F12),可以在Swing Inspector主界面中显示对应组件信息,并高亮当前Component。

2. 可以在Swing Inspector组件树中联动到用户界面,即双向联动,且不需要提供界面的源代码。

3. Applet支持,可以定位嵌入到任何网页中的applet界面。

4. 强大的window捕获功能,可以捕获加载agent的jvm创建的所有Swing/AWT窗口(网页中的applet,浏览器加载appet/webstart后启动的console窗口),模式对话框等。

5. 绿色,无需安装,只需给java命令添加一行参数,即可启动Swing Inspector。

6. 支持所有的AWT/Swing程序,netbeans、visualvm等。

7. 强大的表达式支持,允许对选定组进执行表达式运算,实时显示计算结果,运算结果支持属性浏览和编辑。

8. 强大的Javascript支持功能,支持用javascript实时修改用户界面中的组件,执行脚本后立即生效。

9. 高性能,核心功能采用c/c++实现,直接操纵jvm,对性能影响很小,主界面采用lazy机制,刷新组件时只更新可见viewer。属性编辑器可直接修改选定的组件属性,且直接生效。

10. 可以记录组件添加到parent时的stacktrace,可以快速定位到相应的代码行。

11. 简单易用,快捷键与常用软件一致(F5刷新、Alt+Left后退,Alt+Right前进等),界面非常简洁、直观,没有学习成本。

12. 免费,为软件行业发展尽一份力量是我们的宗旨

 

 

作者:: 老哇的爪子 Attilax 艾龙,  EMAIL:1466519819@qq.com

转载请注明来源: http://blog.csdn.net/attilax

 

2. 类似spylite firebug

3. Eclipse  vm param

 

-agentpath:E:\swing-inspector-windows-1.2.2_beta7\Win32\swing-inspector-agent.dll

4. Cltr+f12显示主界面

 

5. Ctrl+鼠标找到控件

 

 

 

Create StackTrace - javax.swing.JLabel@7293796
    com.openbravo.pos.sales.JPanelTicket.initComponents(JPanelTicket.java:1226)
    com.openbravo.pos.sales.JPanelTicket.(JPanelTicket.java:187)
    com.openbravo.pos.sales.JPanelTicketSales.(JPanelTicketSales.java:18)
    aaaAtiDslParser.aaa33.main(aaa33.java:29

 

 

6. javaagent的主要功能如下:

· 可以在加载class文件之前做拦截,对字节码做修改 

· 可以在运行期对已加载类的字节码做变更,但是这种情况下会有很多的限制,后面会详细说 

· 还有其他一些小众的功能 

获取所有已经加载过的类 

获取所有已经初始化过的类(执行过clinit方法,是上面的一个子集) 

获取某个对象的大小 

将某个jar加入到bootstrap classpath里作为高优先级被bootstrapClassloader加载 

将某个jar加入到classpath里供AppClassloard去加载 

设置某些native方法的前缀,主要在查找native方法的时候做规则匹配 

 

 

7. JPDA(Java Platform Debugger Architecture)是 Java 平台调试体系结构的缩写。

通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。 JPDA 主要由三个部分组成:Java 虚拟机工具接口(JVMTI)、Java 调试线协议(JDWP),以及 Java 调试接口(JDI)。

 

 

7.1. Java 调试接口的特点

Java 语言是第一个使用虚拟机概念的流行的编程语言,正是因为虚拟机的存在,使很多事情变得简单而轻松,掌握了虚拟机,就掌握了内存分配、线程管理、即时优化等等运行态。同样的,Java 调试的本质,就是和虚拟机打交道,通过操作虚拟机来达到观察调试我们自己代码的目的。这个特点决定了 Java 调试接口和以前其他编程语言的巨大区别。

以 C/C++ 的调试为例,目前比较流行的调试工具是 GDB 和微软的 Visual Studio 自带的 debugger,在这种 debugger 中,首先,我们必须编译一个“ debug ”模式的程序,这个会比实际的 release 模式程序大很多。其次,在调试过程中,debugger 将会深层接入程序的运行,掌握和控制运行态的一些信息,并将这些信息及时返回。这种介入对运行的效率和内存占用都有一定的需求。基于这些需求,这些 Debugger 本身事实上是提供了,或者说,创建和管理了一个运行态,因此他们的程序算法比较复杂,个头都比较大。对于远端的调试,GDB 也没有很好的默认实现,当然,C/C++ 在这方面也没有特别大的需求。

 

 

而 Java 则不同,由于 Java 的运行态已经被虚拟机所很好地管理,因此作为 Java 的 Debugger 无需再自己创造一个可控的运行态,而仅仅需要去操作虚拟机就可以了。 Java 的 JPDA 就是一套为调试和优化服务的虚拟机的操作工具,其中,JVMTI 是整合在虚拟机中的接口,JDWP 是一个通讯层,而 JDI 是前端为开发人员准备好的工具和运行库。

从构架上说,我们可以把 JPDA 看作成是一个 C/S 体系结构的应用,在这个构架下,我们可以方便地通过网络,在任意的地点调试另外一个虚拟机上的程序,这个就很好地解决了部署和测试的问题,尤其满足解决了很多网络时代中的开发应用的需求。前端和后端的分离,也方便用户开发适合于自己的调试工具。

从效率上看,由于 Java 程序本身就是编译成字节码,运行在虚拟机上的,因此调试前后的程序、内存占用都不会有大变化(仅仅是启动一个 JDWP 所需要的内存),任意程度都可以很好地调试,非常方便。而 JPDA 构架下的几个组成部分,JDWP 和 JDI 都比较小,主要的工作可以让虚拟机自己完成。

从灵活性上,Java 调试工具是建立在强大的虚拟机上的,因此,很多前沿的应用,比如动态编译运行,字节码的实时替换等等,都可以通过对虚拟机的改进而得到实现。随着虚拟机技术的逐步发展和深入,各种不同种类,不同应用领域中虚拟机的出现,各种强大的功能的加入,给我们的调试工具也带来很多新的应用。

总而言之,一个先天的,可控的运行态给 Java 的调试工作,给 Java 调试接口带来了极大的优势和便利。通过 JPDA 这个标准,我们可以从虚拟机中得到我们所需要的信息,完成我们所希望的操作,更好地开发我们的程序。

 

7.2. JPDA 组成模块

JPDA 定义了一个完整独立的体系,它由三个相对独立的层次共同组成,而且规定了它们三者之间的交互方式,或者说定义了它们通信的接口。这三个层次由低到高分别是 Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)。这三个模块把调试过程分解成几个很自然的概念:调试者(debugger)和被调试者(debuggee),以及他们中间的通信器。被调试者运行于我们想调试的 Java 虚拟机之上,它可以通过 JVMTI 这个标准接口,监控当前虚拟机的信息;调试者定义了用户可使用的调试接口,通过这些接口,用户可以对被调试虚拟机发送调试命令,同时调试者接受并显示调试结果。在调试者和被调试着之间,调试命令和调试结果,都是通过 JDWP 的通讯协议传输的。所有的命令被封装成 JDWP 命令包,通过传输层发送给被调试者,被调试者接收到 JDWP 命令包后,解析这个命令并转化为 JVMTI 的调用,在被调试者上运行。类似的,JVMTI 的运行结果,被格式化成 JDWP 数据包,发送给调试者并返回给 JDI 调用。而调试器开发人员就是通过 JDI 得到数据,发出指令。图 展示了这个过程:

7.2.1.1.1. 图 2. JPDA 模块层次

当然,开发人员完全可以不使用完整的三个层次,而是基于其中的某一个层次开发自己的应用。比如您完全可以仅仅依靠通过 JVMTI 函数开发一个调试工具,而不使用 JDWP 和 JDI,只使用自己的通讯和命令接口。当然,除非是有特殊的需求,利用已有的实现会使您事半功倍,避免重复发明轮子。

这三个模块我们会在后续文章中分别详细介绍,这里我们简单介绍它们的主要功能:

 

7.3. JVMTI 的简介

JVMTIJVM Tool Interface)是 Java 虚拟机所提供的 native 编程接口,是 JVMPIJava Virtual Machine Profiler Interface)和 JVMDIJava Virtual Machine Debug Interface)的更新版本。从这个 API 的发展历史轨迹中我们就可以知道,JVMTI 提供了可用于 debug 和 profiler 的接口;同时,在 Java 5/6 中,虚拟机接口也增加了监听(Monitoring),线程分析(Thread analysis)以及覆盖率分析(Coverage Analysis)等功能。正是由于 JVMTI 的强大功能,它是实现 Java 调试器,以及其它 Java 运行态测试与分析工具的基础。

JVMTI 并不一定在所有的 Java 虚拟机上都有实现,不同的虚拟机的实现也不尽相同。不过在一些主流的虚拟机中,比如 Sun 和 IBM,以及一些开源的如 Apache Harmony DRLVM 中,都提供了标准 JVMTI 实现。

JVMTI 是一套本地代码接口,因此使用 JVMTI 需要我们与 C/C++ 以及 JNI 打交道。事实上,开发时一般采用建立一个 Agent 的方式来使用 JVMTI,它使用 JVMTI 函数,设置一些回调函数,并从 Java 虚拟机中得到当前的运行态信息,并作出自己的判断,最后还可能操作虚拟机的运行态。把 Agent 编译成一个动态链接库之后,我们就可以在 Java 程序启动的时候来加载它(启动加载模式),也可以在 Java 5 之后使用运行时加载(活动加载模式)。

· -agentlib:agent-lib-name=options

· -agentpath:path-to-agent=options

 

 

7.4. Agent 的工作过程

7.4.1. 启动

Agent 是在 Java 虚拟机启动之时加载的,这个加载处于虚拟机初始化的早期,在这个时间点上:

· 所有的 Java 类都未被初始化;

· 所有的对象实例都未被创建;

· 因而,没有任何 Java 代码被执行;

但在这个时候,我们已经可以:

· 操作 JVMTI 的 Capability 参数;

· 使用系统参数;

动态库被加载之后,虚拟机会先寻找一个 Agent 入口函数:

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)

在这个函数中,虚拟机传入了一个 JavaVM 指针,以及命令行的参数。通过 JavaVM,我们可以获得 JVMTI 的指针,并获得 JVMTI 函数的使用能力,所有的 JVMTI 函数都通过这个 jvmtiEnv 获取,不同的虚拟机实现提供的函数细节可能不一样,但是使用的方式是统一的。

jvmtiEnv *jvmti; 

(*jvm)->GetEnv(jvm, &jvmti, JVMTI_VERSION_

7.5. JVMTI 基本功能

JVMTI 的功能非常丰富,包含了虚拟机中线程、内存 堆 栈,类 方法 变量,事件 定时器处理等等 20 多类功能,下面我们介绍一下,并举一些简单列子。

7.5.1. 事件处理和回调函数

从上文我们知道,使用 JVMTI 一个基本的方式就是设置回调函数,在某些事件发生的时候触发并作出相应的动作。因此这一部分的功能非常基本,当前版本的 JVMTI 提供了许多事件(Event)的回调,包括虚拟机初始化、开始运行、结束,类的加载,方法出入,线程始末等等。如果想对这些事件进行处理,我们需要首先为该事件写一个函数,然后在 jvmtiEventCallbacks 这个结构中指定相应的函数指针。比如,我们对线程启动感兴趣,并写了一个 HandleThreadStart 函数,那么我们需要在 Agent_OnLoad 函数里加入:

 

7.5.2. 内存控制和对象获取

内存控制是一切运行态的基本功能。 JVMTI 除了提供最简单的内存申请和撤销之外(这块内存不受 Java 堆管理,开发人员需要自行进行清理工作,不然会造成内存泄漏),也提供了对 Java 堆的操作。众所周知,Java 堆中存储了 Java 的类、对象和基本类型(Primitive),通过对堆的操作,开发人员可以很容易的查找任意的类、对象,甚至可以强行执行垃圾收集工作。 JVMTI 中对 Java 堆的操作与众不同,它没有提供一个直接获取的方式(由此可见,虚拟机对对象的管理并非是哈希表,而是某种树 图方式),而是使用一个迭代器(iterater)的方式遍历:

7.5.3. 线程和锁

线程是 Java 运行态中非常重要的一个部分,在 JVMTI 中也提供了很多 API 进行相应的操作,包括查询当前线程状态,暂停,恢复或者终端线程,还可以对线程锁进行操作。开发者可以获得特定线程所拥有的锁:

jvmtiError GetOwnedMonitorInfo(jvmtiEnv* env, 

    jthread thread, 

    jint* owned_monitor_count_ptr, 

    jobject** owned_monitors_ptr)

也可以获得当前线程正在等待的锁:

jvmtiError GetCurrentContendedMonitor(jvmtiEnv* env, 

    jthread thread, 

    jobject* monitor_ptr)

 

7.5.4. 调试功能

调试功能是 JVMTI 的基本功能之一,这主要包括了设置断点、调试(step)等,在 JVMTI 里面,设置断点的 API 本身很简单:

jvmtiError SetBreakpoint(jvmtiEnv* env, 

    jmethodID method, 

    jlocation location)

 

7.6. 主要部分

7.6.1. Java 虚拟机工具接口(JVMTI)

JVMTIJava Virtual Machine Tool Interface)即指 Java 虚拟机工具接口,它是一套由虚拟机直接提供的 native 接口,它处于整个 JPDA 体系的最底层,所有调试功能本质上都需要通过 JVMTI 来提供。通过这些接口,开发人员不仅调试在该虚拟机上运行的 Java 程序,还能查看它们运行的状态,设置回调函数,控制某些环境变量,从而优化程序性能。我们知道,JVMTI 的前身是 JVMDI 和 JVMPI,它们原来分别被用于提供调试 Java 程序以及 Java 程序调节性能的功能。在 J2SE 5.0 之后 JDK 取代了 JVMDI 和 JVMPI 这两套接口,JVMDI 在最新的 Java SE 6 中已经不提供支持,而 JVMPI 也计划在 Java SE 7 后被彻底取代。

7.6.2. Java 调试线协议(JDWP)

JDWPJava Debug Wire Protocol)是一个为 Java 调试而设计的一个通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。在 JPDA 体系中,作为前端(front-end)的调试者(debugger)进程和后端(back-end)的被调试程序(debuggee)进程之间的交互数据的格式就是由 JDWP 来描述的,它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的 JVMTI 和 JDI 的通信通畅。比如在 Sun 公司提供的实现中,它提供了一个名为 jdwp.dlljdwp.so)的动态链接库文件,这个动态库文件实现了一个 Agent,它会负责解析前端发出的请求或者命令,并将其转化为 JVMTI 调用,然后将 JVMTI 函数的返回值封装成 JDWP 数据发还给后端。

另外,这里需要注意的是 JDWP 本身并不包括传输层的实现,传输层需要独立实现,但是 JDWP 包括了和传输层交互的严格的定义,就是说,JDWP 协议虽然不规定我们是通过 EMS 还是快递运送货物的,但是它规定了我们传送的货物的摆放的方式。在 Sun 公司提供的 JDK 中,在传输层上,它提供了 socket 方式,以及在 Windows 上的 shared memory 方式。当然,传输层本身无非就是本机内进程间通信方式和远端通信方式,用户有兴趣也可以按 JDWP 的标准自己实现。

7.6.3. Java 调试接口(JDI)

JDIJava Debug Interface)是三个模块中最高层的接口,在多数的 JDK 中,它是由 Java 语言实现的。 JDI 由针对前端定义的接口组成,通过它,调试工具开发人员就能通过前端虚拟机上的调试器来远程操控后端虚拟机上被调试程序的运行,JDI 不仅能帮助开发人员格式化 JDWP 数据,而且还能为 JDWP 数据传输提供队列、缓存等优化服务。从理论上说,开发人员只需使用 JDWP 和 JVMTI 即可支持跨平台的远程调试,但是直接编写 JDWP 程序费时费力,而且效率不高。因此基于 Java 的 JDI 层的引入,简化了操作,提高了开发人员开发调试程序的效率。

表 总结了三个模块的不同点:

7.6.3.1.1. 表 1. JPDA 层次比较

模块

层次

编程语言

作用

JVMTI

底层

C

获取及控制当前虚拟机状态

JDWP

中介层

C

定义 JVMTI 和 JDI 交互的数据格式

JDI

高层

Java

提供 Java API 来远程控制被调试虚拟机

 

8. 找到源码

   this.m_jTotalEuros = new JLabel();

    this.m_jLblTotalEuros1 = new JLabel();

this.m_jSubtotalEuros = new JLabel();

 

 

参考

深入 Java 调试体系,第 2 部分  JVMTI 和 Agent 实现.htm

JVMTI开发教程之一个简单的Agent - 飞鸟Blog - 博客频道 - CSDN.NET.htm

JVM的动态agent机制 在main函数启动之后运行agent - CSDN博客.htm

JVM源码分析之javaagent原理完全解读.htm

 类似资料: