引入:
上文主要讲解了JDI的连接模块来建立Debugger到Target VM之间的连接,这里主要讲解事件请求和处理模块。它们都在com.sun.jdi.event和com.sun.jdi.request包中。
分析:
Part 1:查看JDI中定义的事件类型
JDI中事件的接口叫Event .
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:事件集的概念
事件集是事件发送的最小单位,并且事件集一旦被创建,则不可以被修改。
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()方法来给某个事件请求添加一个或者多个过滤器:
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方法来列出各种类型的事件请求。
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插件来显示结果。
总结:
在此文章中,我们涉及到了多个概念,这里把其中的类模型概括下:
转载于:https://blog.51cto.com/supercharles888/1588043