引入:
上文主要讲解了JDI的连接模块来建立Debugger到Target VM之间的连接,这里主要讲解事件请求和处理模块。它们都在com.sun.jdi.event和com.sun.jdi.request包中。
分析:
Part 1:查看JDI中定义的事件类型
JDI中事件的接口叫Event .
1
2
3
4
|
public
abstract
interface
Event
extends
Mirror
{
public
abstract
EventRequest request();
}
|
它定义了18种具体的事件类型,如下:
ClassPrepareEvent | 装载某个指定的类所引发的事件 |
ClassUnloadEvent | 卸载某个指定的类所引发的事件 |
BreakingpointEvent | 设置断点所引发的事件 |
ExceptionEvent | 目标虚拟机运行中抛出指定异常所引发的事件 |
MethodEntryEvent | 进入某个指定方法体时引发的事件 |
MethodExitEvent | 某个指定方法执行完成后引发的事件 |
MonitorContendedEnteredEvent | 线程已经进入某个指定 Monitor 资源所引发的事件 |
MonitorContendedEnterEvent | 线程将要进入某个指定 Monitor 资源所引发的事件 |
MonitorWaitedEvent | 线程完成对某个指定 Monitor 资源等待所引发的事件 |
MonitorWaitEvent | 线程开始等待对某个指定 Monitor 资源所引发的事件 |
StepEvent | 目标应用程序执行下一条指令或者代码行所引发的事件 |
AccessWatchpointEvent | 查看类的某个指定 Field 所引发的事件 |
ModificationWatchpointEvent | 修改类的某个指定 Field 值所引发的事件 |
ThreadDeathEvent | 某个指定线程运行完成所引发的事件 |
ThreadStartEvent | 某个指定线程开始运行所引发的事件 |
VMDeathEvent | 目标虚拟机停止运行所以的事件 |
VMDisconnectEvent | 目标虚拟机与调试器断开链接所引发的事件 |
VMStartEvent | 目标虚拟机初始化时所引发的事件 |
Part 2:事件集的概念
事件集是事件发送的最小单位,并且事件集一旦被创建,则不可以被修改。
1
2
3
4
5
6
7
8
|
public
abstract
interface
EventSet
extends
Mirror, Set<Event>
{
public
abstract
int
suspendPolicy();
public
abstract
EventIterator eventIterator();
public
abstract
void
resume();
}
|
它也提供了迭代器来访问事件集内的事件。
Part 3:事件队列
事件队列(EventQueue)的拥有者是目标虚拟机,EventQueue 将这些事件集以“先进先出”策略依次地发送到调试器端。EventQueue 负责管理来自目标虚拟机的事件,一个被调试的目标虚拟机上有且仅有一个 EventQueue实例。特别地,随着一次事件集的发送,目标虚拟机上可能会有一部分的线程因此而被挂起。如果一直不恢复这些线程,有可能会导致目标虚拟机挂机。
Part 4: JDI事件请求
正如Part1 所说,Event接口定义了request方法,该方法会返回由调试器Debugger发出的针对该事件的事件请求(EventRequest)。事件请求是由调试器向目标虚拟机发出的,目的是请求目标虚拟机在发生指定的事件后通知调试器。只有当调试器发出的请求与目标虚拟机上发生的事件匹配时,这些事件才会被分发到各个事件集,进而等待发送至调试器端。
(注意:这里可能有点绕口,一句话概括就是 EventRequest总是由Debugger发向Target VM ,而当请求与目标虚拟机上发生事件匹配,则事件会被归到EventSet中,EventSet会被Target VM的EventQueue所管理,并且按照FIFO原则发送到Debugger)
当然了,Debugger发送给Target VM的所有事件请求,不一定Target VM 都感兴趣。因此JDI提供了事件的过滤机制,来删选出最终真正要发送给Target VM的事件。
EventRequest中提供了一组addXXXFilter()方法来给某个事件请求添加一个或者多个过滤器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
public
void
addCountFilter(
int
count)
throws
InvalidRequestStateException
{
checkDisabled();
if
(
this
.fCountFilters ==
null
) {
this
.fCountFilters =
new
ArrayList();
}
this
.fCountFilters.add(
new
Integer(count));
}
public
void
addThreadFilter(ThreadReference threadFilter)
throws
ObjectCollectedException, VMMismatchException, InvalidRequestStateException
{
checkVM(threadFilter);
checkDisabled();
if
(threadFilter.isCollected())
throw
new
ObjectCollectedException();
if
(
this
.fThreadFilters ==
null
) {
this
.fThreadFilters =
new
ArrayList();
}
this
.fThreadFilters.add(threadFilter);
}
public
void
addClassFilter(ReferenceType filter)
throws
VMMismatchException, InvalidRequestStateException
{
checkVM(filter);
checkDisabled();
if
(
this
.fClassFilterRefs ==
null
) {
this
.fClassFilterRefs =
new
ArrayList();
}
this
.fClassFilterRefs.add(filter);
}
public
void
addClassFilter(String filter)
throws
InvalidRequestStateException
{
checkDisabled();
if
(
this
.fClassFilters ==
null
) {
this
.fClassFilters =
new
ArrayList();
}
this
.fClassFilters.add(filter);
}
public
void
addClassExclusionFilter(String filter)
throws
InvalidRequestStateException
{
checkDisabled();
if
(
this
.fClassExclusionFilters ==
null
) {
this
.fClassExclusionFilters =
new
ArrayList();
}
this
.fClassExclusionFilters.add(filter);
}
public
void
addLocationFilter(LocationImpl location)
throws
VMMismatchException
{
checkDisabled();
checkVM(location);
if
(
this
.fLocationFilters ==
null
) {
this
.fLocationFilters =
new
ArrayList();
}
this
.fLocationFilters.add(location);
}
public
void
addExceptionFilter(ReferenceTypeImpl refType,
boolean
notifyCaught,
boolean
notifyUncaught)
throws
VMMismatchException
{
checkDisabled();
if
(refType !=
null
) {
checkVM(refType);
}
if
(
this
.fExceptionFilters ==
null
) {
this
.fExceptionFilters =
new
ArrayList();
}
ExceptionFilter filter =
new
ExceptionFilter();
filter.fException = refType;
filter.fNotifyCaught = notifyCaught;
filter.fNotifyUncaught = notifyUncaught;
this
.fExceptionFilters.add(filter);
}
public
void
addFieldFilter(FieldImpl field)
throws
VMMismatchException
{
checkDisabled();
checkVM(field);
if
(
this
.fFieldFilters ==
null
) {
this
.fFieldFilters =
new
ArrayList();
}
this
.fFieldFilters.add(field);
}
public
void
addStepFilter(ThreadReferenceImpl thread,
int
size,
int
depth)
throws
VMMismatchException
{
checkDisabled();
checkVM(thread);
if
(
this
.fThreadStepFilters ==
null
) {
this
.fThreadStepFilters =
new
ArrayList();
}
ThreadStepFilter filter =
new
ThreadStepFilter();
filter.fThread = thread;
filter.fThreadStepSize = size;
filter.fThreadStepDepth = depth;
this
.fThreadStepFilters.add(filter);
}
public
void
addInstanceFilter(ObjectReference instance)
{
checkDisabled();
checkVM(instance);
if
(
this
.fInstanceFilters ==
null
) {
this
.fInstanceFilters =
new
ArrayList();
}
this
.fInstanceFilters.add(instance);
}
public
void
addSourceNameFilter(String pattern)
{
checkDisabled();
if
(
this
.fSourceNameFilters ==
null
) {
this
.fSourceNameFilters =
new
ArrayList();
}
this
.fSourceNameFilters.add(pattern);
}
|
Part 5: Target VM对于事件请求(EventRequest)的管理
在JDI中,事件请求的管理是通过EventRequestManager来完成的。它有许多createXXXRequest方法来创建不同类型的事件请求,也有许多deleteXXXRequest方法来删除不同类型的事件请求,还有xxxRequests方法来列出各种类型的事件请求。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
package
com.sun.jdi.request;
import
com.sun.jdi.Field;
import
com.sun.jdi.Location;
import
com.sun.jdi.Mirror;
import
com.sun.jdi.ReferenceType;
import
com.sun.jdi.ThreadReference;
import
java.util.List;
public
abstract
interface
EventRequestManager
extends
Mirror
{
public
abstract
ClassPrepareRequest createClassPrepareRequest();
public
abstract
ClassUnloadRequest createClassUnloadRequest();
public
abstract
ThreadStartRequest createThreadStartRequest();
public
abstract
ThreadDeathRequest createThreadDeathRequest();
public
abstract
ExceptionRequest createExceptionRequest(ReferenceType paramReferenceType,
boolean
paramBoolean1,
boolean
paramBoolean2);
public
abstract
MethodEntryRequest createMethodEntryRequest();
public
abstract
MethodExitRequest createMethodExitRequest();
public
abstract
MonitorContendedEnterRequest createMonitorContendedEnterRequest();
public
abstract
MonitorContendedEnteredRequest createMonitorContendedEnteredRequest();
public
abstract
MonitorWaitRequest createMonitorWaitRequest();
public
abstract
MonitorWaitedRequest createMonitorWaitedRequest();
public
abstract
StepRequest createStepRequest(ThreadReference paramThreadReference,
int
paramInt1,
int
paramInt2);
public
abstract
BreakpointRequest createBreakpointRequest(Location paramLocation);
public
abstract
AccessWatchpointRequest createAccessWatchpointRequest(Field paramField);
public
abstract
ModificationWatchpointRequest createModificationWatchpointRequest(Field paramField);
public
abstract
VMDeathRequest createVMDeathRequest();
public
abstract
void
deleteEventRequest(EventRequest paramEventRequest);
public
abstract
void
deleteEventRequests(List<?
extends
EventRequest> paramList);
public
abstract
void
deleteAllBreakpoints();
public
abstract
List<StepRequest> stepRequests();
public
abstract
List<ClassPrepareRequest> classPrepareRequests();
public
abstract
List<ClassUnloadRequest> classUnloadRequests();
public
abstract
List<ThreadStartRequest> threadStartRequests();
public
abstract
List<ThreadDeathRequest> threadDeathRequests();
public
abstract
List<ExceptionRequest> exceptionRequests();
public
abstract
List<BreakpointRequest> breakpointRequests();
public
abstract
List<AccessWatchpointRequest> accessWatchpointRequests();
public
abstract
List<ModificationWatchpointRequest> modificationWatchpointRequests();
public
abstract
List<MethodEntryRequest> methodEntryRequests();
public
abstract
List<MethodExitRequest> methodExitRequests();
public
abstract
List<MonitorContendedEnterRequest> monitorContendedEnterRequests();
public
abstract
List<MonitorContendedEnteredRequest> monitorContendedEnteredRequests();
public
abstract
List<MonitorWaitRequest> monitorWaitRequests();
public
abstract
List<MonitorWaitedRequest> monitorWaitedRequests();
public
abstract
List<VMDeathRequest> vmDeathRequests();
}
|
有一点需要注意的是,这里由EventRequestManager创建的createXXXRequest的事件都是非激活的,因此这些事件请求当发送给Target VM不会起任何作用,除非调用EventRequest的setEnable(true)使得该事件进入激活状态。
Part 6: JDI中Debugger与Target VM之间的事件交互。
Step 1:Debugger调用Target VM的 eventQueue() 和 eventRequestManager() 分别获取唯一的 EventQueue 实例和 EventRequestManager 实例.
Step 2: Debugger通过 EventRequestManager 的 createXXXRequest() 创建需要的事件请求,并添加过滤器和设置挂起策略.
Step 3: Debugger通过EventQueue 获取来自Target VM的事件实例.
这个事件实例包含了许多信息,比如ThreadReference ,StackFrame,LocalVariable, Location,Method等,这些事件信息就包含了当前Target VM的一些现有状态信息和数据,Debugger就用这些数据交给Eclipse的相应的Debugger UI插件来显示结果。
总结:
在此文章中,我们涉及到了多个概念,这里把其中的类模型概括下: