Úvod do rozhrania Java Debug Interface (JDI)

1. Prehľad

Možno sa čudujeme, ako široko uznávané IDE ako IntelliJ IDEA a Eclipse implementujú funkcie ladenia. Tieto nástroje vo veľkej miere závisia od architektúry Java Platform Debugger Architecture (JPDA).

V tomto úvodnom článku sa budeme zaoberať rozhraním Java Debug Interface API (JDI) dostupným v rámci JPDA.

Zároveň, napíšeme vlastný debugger program krok za krokom, oboznámenie sa s praktickými rozhraniami JDI.

2. Úvod do JPDA

Architektúra Java Platform Debugger Architecture (JPDA) je sada dobre navrhnutých rozhraní a protokolov používaných na ladenie Javy.

Poskytuje tri špeciálne navrhnuté rozhrania na implementáciu vlastných debuggerov pre vývojové prostredie v desktopových systémoch.

Na začiatok nám rozhranie Java Virtual Machine Tool Interface (JVMTI) pomáha pri interakcii a kontrole vykonávania aplikácií spustených v JVM.

Potom existuje protokol Java Debug Wire Protocol (JDWP), ktorý definuje protokol používaný medzi testovanou aplikáciou (debuggee) a debuggerom.

Na implementáciu debuggerovej aplikácie sa nakoniec používa rozhranie Java Debug Interface (JDI).

3. Čo je JDI?

Rozhranie Java Debug Interface API je sada rozhraní poskytovaných programom Java na implementáciu rozhrania debuggeru. JDI je najvyššou vrstvou JPDA.

Debugger postavený na JDI môže ladiť aplikácie bežiace v akomkoľvek JVM, ktorý podporuje JPDA. Zároveň ho môžeme zapojiť do ľubovoľnej vrstvy ladenia.

Poskytuje možnosť prístupu k virtuálnemu počítaču a jeho stavu spolu s prístupom k premenným ladiaceho nástroja. Zároveň umožňuje nastaviť body prerušenia, krokovanie, body sledovania a spracovať závity.

4. Inštalácia

Na pochopenie implementácií JDI budeme potrebovať dva samostatné programy - debuggee a debugger.

Najskôr ako debuggee napíšeme ukážkový program.

Vytvorme a JDIExampleDebuggee triedy s pár String premenné a println Vyhlásenia:

public class JDIExampleDebuggee {public static void main (String [] args) {String jpda = "Java Platform Debugger Architecture"; System.out.println ("Ahoj všetci, vítam vás" + jpda); // tu pridať bod zlomu String jdi = "Java Debug Interface"; // tu pridáme bod zlomu a tiež tu vkročíme String text = "Dnes sa ponoríme do" + jdi; System.out.println (text); }}

Potom napíšeme debugger program.

Vytvorme a JDIExampleDebugger trieda s vlastnosťami na uloženie ladiaceho programu (debugClass) a čísla riadkov pre body prerušenia (breakPointLines):

verejná trieda JDIExampleDebugger {súkromná trieda debugClass; private int [] breakPointLines; // zakladatelia a zakladatelia}

4.1. LaunchingConnector

Ladiaci program najskôr vyžaduje konektor na nadviazanie spojenia s cieľovým virtuálnym strojom (VM).

Potom budeme musieť nastaviť debuggee ako konektor hlavný argument. Konektor by mal konečne spustiť VM na ladenie.

Za týmto účelom JDI poskytuje a Bootstrap trieda, ktorá dáva inštanciu súboru LaunchingConnector. The LaunchingConnector poskytuje mapu predvolených argumentov, do ktorých môžeme nastaviť hlavný argument.

Preto pridajme connectAndLaunchVM metóda do Príklad JDIDebugger trieda:

public VirtualMachine connectAndLaunchVM () vyvolá výnimku {LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager () .defaultConnector (); Argumenty mapy = launchingConnector.defaultArguments (); argumenty.get ("main"). setValue (debugClass.getName ()); návrat launchingConnector.launch (argumenty); }

Teraz pridáme hlavný metóda do Príklad JDIDebugger triedy na odladenie JDIExampleDebuggee:

public static void main (String [] args) vyvolá výnimku {JDIExampleDebugger debuggerInstance = nový JDIExampleDebugger (); debuggerInstance.setDebugClass (JDIExampleDebuggee.class); int [] breakPoints = {6, 9}; debuggerInstance.setBreakPointLines (breakPoints); VirtualMachine vm = null; try {vm = debuggerInstance.connectAndLaunchVM (); vm.resume (); } catch (Výnimka e) {e.printStackTrace (); }}

Poďme zostaviť obe naše triedy, JDIExampleDebuggee (debuggee) a JDIExampleDebugger (debugger):

javac -g -cp "/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar" com / baeldung / jdi / *. java

Poďme diskutovať o javac tu použitý podrobne.

The -g voľba generuje všetky ladiace informácie bez ktorých, ako sa môžeme presvedčiť AbsentInformationException.

A -cp pridá toolss.jar v triede na zostavenie tried.

Všetky knižnice JDI sú dostupné pod toolss.jar JDK. Preto nezabudnite pridať toolss.jar v triede kompilácie aj vykonania.

To je všetko, teraz sme pripravení vykonať náš vlastný debugger JDIExampleDebugger:

java -cp "/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar :." JDIExampleDebugger

Všimnite si „:“. s toolss.jar. Toto sa pripojí toolss.jar na cestu ku triede pre aktuálny čas spustenia (v oknách použite „;.“).

4.2. Bootstrap a ClassPrepareRequest

Spustenie ladiaceho programu tu neprinesie žiadne výsledky, pretože sme triedu nepripravili na ladenie a nenastavili sme body prerušenia.

The Virtuálny prístroj trieda má eventRequestManager metóda na vytvorenie rôznych požiadaviek ako ClassPrepareRequest, BreakpointRequesta StepEventRequest.

Pridajme teda enableClassPrepareRequest metóda do JDIExampleDebugger trieda.

Toto vyfiltruje JDIExampleDebuggee triedy a umožňuje ClassPrepareRequest:

public void enableClassPrepareRequest (VirtualMachine vm) {ClassPrepareRequest classPrepareRequest = vm.eventRequestManager (). createClassPrepareRequest (); classPrepareRequest.addClassFilter (debugClass.getName ()); classPrepareRequest.enable (); }

4.3. ClassPrepareEvent a BreakpointRequest

Raz, ClassPrepareRequest pre JDIExampleDebuggee triedy je povolená, vo fronte udalostí VM sa začnú vyskytovať inštancie ClassPrepareEvent.

Použitím ClassPrepareEvent, môžeme získať miesto na nastavenie zarážky a vytvorí a BreakPointRequest.

Ak to chcete urobiť, pridajme setBreakPoints metóda do JDIExampleDebugger trieda:

public void setBreakPoints (VirtualMachine vm, udalosť ClassPrepareEvent) hodí AbsentInformationException {ClassType classType = (ClassType) event.referenceType (); for (int lineNumber: breakPointLines) {Location location = classType.locationsOfLine (lineNumber) .get (0); BreakpointRequest bpReq = vm.eventRequestManager (). CreateBreakpointRequest (umiestnenie); bpReq.enable (); }}

4.4. BreakPointEvent a StackFrame

Zatiaľ sme pripravili triedu na ladenie a nastavili sme body prerušenia. Teraz musíme chytiť BreakPointEvent a zobraziť premenné.

JDI poskytuje StackFrame triedy, aby ste získali zoznam všetkých viditeľných premenných debuggee.

Preto pridajme displayVariables metóda do JDIExampleDebugger trieda:

public void displayVariables (udalosť LocatableEvent) hodí IncompatibleThreadStateException, AbsentInformationException {StackFrame stackFrame = event.thread (). frame (0); if (stackFrame.location (). toString (). contains (debugClass.getName ())) {Map visibleVariables = stackFrame .getValues ​​(stackFrame.visibleVariables ()); System.out.println ("Premenné na" + stackFrame.location (). ToString () + ">"); pre (položka Map.Entry: visibleVariables.entrySet ()) {System.out.println (entry.getKey (). name () + "=" + entry.getValue ()); }}}

5. Debug Target

V tomto kroku všetko, čo potrebujeme, je aktualizovať hlavný metóda JDIExampleDebugger začať ladiť.

Preto použijeme už diskutované metódy ako enableClassPrepareRequest, setBreakPointsa premenné displeja:

try {vm = debuggerInstance.connectAndLaunchVM (); debuggerInstance.enableClassPrepareRequest (vm); EventSet eventSet = null; while ((eventSet = vm.eventQueue (). remove ())! = null) {for (Event event: eventSet) {if (event instanceof ClassPrepareEvent) {debuggerInstance.setBreakPoints (vm, (ClassPrepareEvent) event); } if (event instanceof BreakpointEvent) {debuggerInstance.displayVariables ((BreakpointEvent) event); } vm.resume (); }}} catch (VMDisconnectedException e) {System.out.println ("Virtuálny počítač je odpojený."); } catch (Výnimka e) {e.printStackTrace (); }

Po prvé, poďme si zostaviť Príklad JDIDebugger triedy opäť s už diskutovanými javac príkaz.

A nakoniec vykonáme ladiaci program spolu so všetkými zmenami, aby sme videli výstup:

Premenné na com.baeldung.jdi.JDIExampleDebuggee: 6> args = inštancia java.lang.String [0] (id = 93) Premenné na com.baeldung.jdi.JDIExampleDebuggee: 9> jpda = „Java Platform Debugger Architecture“ args = inštancia java.lang.String [0] (id = 93) Virtuálny počítač je odpojený.

Hurá! Úspešne sme odladili JDIExampleDebuggee trieda. Zároveň sme zobrazili hodnoty premenných v miestach prerušenia (riadok číslo 6 a 9).

Preto je náš vlastný debugger pripravený.

5.1. StepRequest

Ladenie tiež vyžaduje krokovanie kódu a kontrolu stavu premenných v ďalších krokoch. Preto v bode zlomu vytvoríme požiadavku na krok.

Pri vytváraní inštancie súboru StepRequest, musíme poskytnúť veľkosť a hĺbku schodu. Definujeme STEP_LINE a PREKROČIŤ resp.

Poďme napísať metódu na povolenie žiadosti o krok.

Pre jednoduchosť začneme šliapať na posledný bod zlomu (riadok číslo 9):

public void enableStepRequest (VirtualMachine vm, udalosť BreakpointEvent) {// povoliť požiadavku na krok pre posledný bod zlomu, ak (event.location (). toString (). contains (debugClass.getName () + ":" + breakPointLines [breakPointLines.length- 1])) {StepRequest stepRequest = vm.eventRequestManager () .createStepRequest (event.thread (), StepRequest.STEP_LINE, StepRequest.STEP_OVER); stepRequest.enable (); }}

Teraz môžeme aktualizovať hlavný metóda JDIExampleDebugger, aby ste povolili požiadavku na krok, keď je to BreakPointEvent:

if (event instanceof BreakpointEvent) {debuggerInstance.enableStepRequest (vm, (BreakpointEvent) event); }

5.2. StepEvent

Podobne ako v BreakPointEvent, môžeme tiež zobraziť premenné na StepEvent.

Poďme aktualizovať hlavný zodpovedajúcim spôsobom:

if (event instanceof StepEvent) {debuggerInstance.displayVariables ((StepEvent) event); }

Nakoniec vykonáme debugger, aby sme pri prechádzaní kódom videli stav premenných:

Premenné na com.baeldung.jdi.JDIExampleDebuggee: 6> args = inštancia java.lang.String [0] (id = 93) Premenné na com.baeldung.jdi.JDIExampleDebuggee: 9> args = inštancia java.lang.String [0] (id = 93) jpda = "Java Platform Debugger Architecture" Premenné na com.baeldung.jdi.JDIExampleDebuggee: 10> args = inštancia java.lang.String [0] (id = 93) jpda = "Java Platform Debugger Architecture "jdi =" Java Debug Interface "Premenné na com.baeldung.jdi.JDIExampleDebuggee: 11> args = inštancia java.lang.String [0] (id = 93) jpda =" Java Platform Debugger Architecture "jdi =" Java Debug Interface "text =" Dnes sa ponoríme do Java Debug Interface "Premenné na com.baeldung.jdi.JDIExampleDebuggee: 12> args = inštancia java.lang.String [0] (id = 93) jpda =" Architektúra ladenia platformy Java "jdi =" Rozhranie ladenia Java "text =" Dnes sa ponoríme do rozhrania ladenia Java "Virtuálny počítač je odpojený.

Ak porovnáme výstup, uvedomíme si, že ladiaci program vstúpil z riadku číslo 9 a zobrazuje premenné vo všetkých ďalších krokoch.

6. Prečítajte si výstup vykonania

Mohli by sme si to všimnúť println vyhlásenia JDIExampleDebuggee triedy neboli súčasťou výstupu debuggeru.

Podľa dokumentácie JDI, ak spustíme VM prostredníctvom LaunchingConnector, jeho výstupné a chybové prúdy musia byť načítané serverom Proces objekt.

Pridajme ju preto k konečne doložka našej hlavný metóda:

nakoniec {InputStreamReader reader = nový InputStreamReader (vm.process (). getInputStream ()); Zapisovač OutputStreamWriter = nový OutputStreamWriter (System.out); char [] buf = nový char [512]; reader.read (buf); spisovateľ.písať (buf); writer.flush (); }

Teraz spustením debugger programu tiež pridáte println vyhlásenia z JDIExampleDebuggee triedy do výstupu ladenia:

Ahoj všetci, vitajte v architektúre Java Platform Debugger Architecture Dnes sa ponoríme do rozhrania Java Debug Interface

7. Záver

V tomto článku sme preskúmali rozhranie API Java Debug Interface (JDI) dostupné v rámci architektúry Java Platform Debugger Architecture (JPDA).

Počas toho sme vytvorili vlastný debugger využívajúci praktické rozhrania poskytované JDI. Zároveň sme do ladiaceho programu pridali aj schopnosť krokovania.

Pretože to bol iba úvod do JDI, odporúča sa pozrieť sa na implementácie ďalších rozhraní dostupných v JDI API.

Ako obvykle sú všetky implementácie kódu dostupné na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found