引入:java
上文主要講解了JDI的鏈接模塊來創建Debugger到Target VM之間的鏈接,這裏主要講解事件請求和處理模塊。它們都在com.sun.jdi.event和com.sun.jdi.request包中。ide
分析:this
Part 1:查看JDI中定義的事件類型spa
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:事件集的概念調試
事件集是事件發送的最小單位,而且事件集一旦被建立,則不能夠被修改。blog
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插件來顯示結果。
總結:
在此文章中,咱們涉及到了多個概念,這裏把其中的類模型歸納下: