Bevezetés a Java hibakeresési felületbe (JDI)

1. Áttekintés

Kíváncsi lehetünk arra, hogy az olyan széles körben elismert IDE-k, mint az IntelliJ IDEA és az Eclipse, hogyan hajtják végre a hibakeresési szolgáltatásokat. Ezek az eszközök nagyban támaszkodnak a Java Platform Debugger Architecture-re (JPDA).

Ebben a bevezető cikkben a JPDA alatt elérhető Java Debug Interface API-t (JDI) tárgyaljuk.

Ugyanabban az időben, írunk egy egyedi hibakereső programot lépésről lépésre ismerkedjünk meg a praktikus JDI interfészekkel.

2. Bevezetés a JPDA-ba

A Java Platform Debugger Architecture (JPDA) egy jól megtervezett interfészek és protokollok összessége, amelyeket a Java hibakereséséhez használnak.

Három speciálisan tervezett felületet kínál az egyedi hibakeresők megvalósításához az asztali rendszerek fejlesztői környezetéhez.

Először is, a Java Virtual Machine Tool Interface (JVMTI) segít kölcsönhatásban és ellenőrizni a JVM-ben futó alkalmazások futtatását.

Ezután ott van a Java Debug Wire Protocol (JDWP), amely meghatározza a tesztelt alkalmazás (debuggee) és a debugger között használt protokollt.

Végül a Java Debug Interface (JDI) a hibakereső alkalmazás megvalósítására szolgál.

3. Mi az JDI?

A Java Debug Interface API a Java által biztosított interfészek összessége a hibakereső kezelőfelületének megvalósításához. A JDI a JPDA legmagasabb rétege.

A JDI-vel felépített hibakereső bármilyen JPV-t támogató JVM-ben futó alkalmazásokat hibakeresésre képes. Ugyanakkor a hibakeresés bármely rétegébe bekapcsolhatjuk.

Lehetővé teszi a virtuális gép és annak állapotának elérését, valamint a hibakereső változóihoz való hozzáférést. Ugyanakkor lehetővé teszi a töréspontok, a lépések, az ellenőrzési pontok és a szálak kezelését.

4. Beállítás

Két külön programra lesz szükségünk - egy hibakeresőre és egy hibakeresőre -, hogy megértsük a JDI megvalósításait.

Először írunk egy mintaprogramot hibakeresőként.

Hozzunk létre egy JDIExampleDuguggee osztály néhány Húr változók és println nyilatkozatok:

public class JDIExampleDebuggee {public static void main (String [] args) {String jpda = "Java Platform Debugger Architecture"; System.out.println ("Sziasztok mindenkit, üdvözlünk a" + jpda-ban); // adjon itt töréspontot String jdi = "Java Debug Interface"; // adjon itt töréspontot, és lépjen ide is String text = "Ma belemerülünk" + jdi; System.out.println (szöveg); }}

Ezután írunk egy hibakereső programot.

Hozzunk létre egy JDIExampleDebugger osztály tulajdonságokkal a hibakereső program megtartására (debugClass) és a töréspontok sorszáma (breakPointLines):

public class JDIExampleDebugger {private Class debugClass; private int [] breakPointLines; // szerelők és beállítók}

4.1. LaunchingConnector

Először egy hibakeresőnek csatlakozóra van szüksége a kapcsolat létrehozásához a virtuális géppel (virtuális gép).

Ezután be kell állítanunk a hibakeresőt csatlakozóként fő- érv. Végül az összekötőnek elindítania kell a virtuális gépet a hibakereséshez.

Ehhez a JDI biztosítja a Bootstrap osztály, amely megadja a LaunchingConnector. A LaunchingConnector megadja az alapértelmezett argumentumok térképét, amelyben beállíthatjuk a fő- érv.

Ezért tegyük hozzá a connectAndLaunchVM módszer a JDIDebuggerExample osztály:

public VirtualMachine connectAndLaunchVM () dobja a Kivételt {LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager () .defaultConnector (); Map argumentumok = launchingConnector.defaultArguments (); argumentumok.get ("main"). setValue (debugClass.getName ()); return launchingConnector.launch (érvek); }

Most hozzáadjuk a fő- módszer a JDIDebuggerExample osztály debug a JDIExampleDuguggee:

public static void main (String [] args) dobja a {JDIExampleDebugger debuggerInstance = new JDIExampleDebugger () kivételt; debuggerInstance.setDebugClass (JDIExampleDebuggee.class); int [] breakPoints = {6, 9}; debuggerInstance.setBreakPointLines (breakPoints); VirtualMachine vm = null; próbáld ki a {vm = debuggerInstance.connectAndLaunchVM () parancsot; vm.resume (); } catch (e kivétel) {e.printStackTrace (); }}

Állítsuk össze mindkét osztályunkat, JDIExampleDuguggee (debuggee) és JDIExampleDebugger (hibakereső):

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

Beszéljük meg a javac itt használt parancs, részletesen.

A -g opció generálja az összes hibakeresési információt amely nélkül láthatjuk AbsentInformationException.

És -cp hozzáadja a eszközök.jar az osztálypályán az osztályok összeállításához.

Az összes JDI könyvtár elérhető a következő címen: eszközök.jar a JDK. Ezért feltétlenül adja hozzá a eszközök.jar az osztályban mind az összeállításnál, mind a végrehajtásnál.

Ez az, most már készen állunk az egyedi hibakereső végrehajtására JDIExampleDebugger:

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

Vegye figyelembe a „:.” val vel eszközök.jar. Ez kiegészül eszközök.jar a classpath-ra az aktuális futási időre (használja a „;.” -t a Windows-on).

4.2. Bootstrap és ClassPrepareRequest

A hibakereső program itt történő végrehajtása nem eredményez eredményeket, mivel nem készítettük fel az osztályt a hibakeresésre és nem állítottuk be a töréspontokat.

A Virtuális gép osztály rendelkezik a eventRequestManager metódus különféle kérések, például ClassPrepareRequest, BreakpointRequest, és StepEventRequest.

Tehát tegyük hozzá a enableClassPrepareRequest módszer a JDIExampleDebugger osztály.

Ez leszűrni a JDIExampleDuguggee osztály és lehetővé teszi a ClassPrepareRequest:

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

4.3. ClassPrepareEvent és BreakpointRequest

Egyszer, ClassPrepareRequest a JDIExampleDuguggee osztály engedélyezve van, a virtuális gép eseménysorában megkezdődnek a ClassPrepareEvent.

Használata ClassPrepareEvent, megkaphatjuk a töréspont beállításának helyét és létrehozunk egy BreakPointRequest.

Ehhez tegyük hozzá a setBreakPoints módszer a JDIExampleDebugger osztály:

public void setBreakPoints (VirtualMachine vm, ClassPrepareEvent esemény) dobja az AbsentInformationException {ClassType classType = (ClassType) esemény.referenceType (); for (int lineNumber: breakPointLines) {Location location = classType.locationsOfLine (lineNumber) .get (0); BreakpointRequest bpReq = vm.eventRequestManager (). CreateBreakpointRequest (hely); bpReq.enable (); }}

4.4. BreakPointEvent és StackFrame

Eddig felkészítettük az osztályt a hibakeresésre és beállítottuk a töréspontokat. Most el kell kapnunk a BreakPointEvent és megjeleníti a változókat.

A JDI biztosítja a StackFrame osztály, hogy megkapja a debuggee összes látható változójának listáját.

Ezért tegyük hozzá a displayVariables módszer a JDIExampleDebugger osztály:

public void displayVariables (LocatableEvent event) az IncompatibleThreadStateException, AbsentInformationException {StackFrame stackFrame = event.thread (). frame (0) dob; if (stackFrame.location (). toString (). tartalmazza (debugClass.getName ())) {Map visibleVariables = stackFrame .getValues ​​(stackFrame.visibleVariables ()); System.out.println ("Változók a" + stackFrame.location (). ToString () + ">" -ban); a (Map.Entry bejegyzéshez: láthatóVariables.entrySet ()) {System.out.println (entry.getKey (). név () + "=" + entry.getValue ()); }}}

5. Debug Target

Ebben a lépésben csak a frissítésre van szükségünk fő- módszere JDIExampleDebugger hogy elkezdjen hibakeresést.

Ezért a már tárgyalt módszereket fogjuk használni enableClassPrepareRequest, setBreakPoints, és displayVariables:

próbáld ki a {vm = debuggerInstance.connectAndLaunchVM () parancsot; debuggerInstance.enableClassPrepareRequest (vm); EventSet eventSet = null; while (((eventSet = vm.eventQueue (). remove ())! = null) {for (Event event: eventSet) {if (eventPrimex of ClassPrepareEvent) {debuggerInstance.setBreakPoints (vm, (ClassPrepareEvent) esemény); } if (a BreakpointEvent esemény példánya) {debuggerInstance.displayVariables ((BreakpointEvent) esemény); } vm.resume (); }}} catch (VMDisconnectedException e) {System.out.println ("A virtuális gép nincs csatlakoztatva."); } catch (e kivétel) {e.printStackTrace (); }

Most először állítsuk össze a JDIDebuggerExample osztály ismét a már tárgyalt javac parancs.

És végül a kimenet megtekintéséhez végrehajtjuk a hibakereső programot az összes módosítással együtt:

Változók a com.baeldung.jdi.JDIExampleDebuggee címen: 6> args = a java.lang.String példánya [0] (id = 93) A com.baeldung.jdi.JDIExampleDebuggee: 9> jpda = "Java Platform Debugger Architecture" változók = a java.lang.String [0] (id = 93) példánya A virtuális gép le van választva.

Hurrá! Sikeresen kijavítottuk a JDIExampleDuguggee osztály. Ugyanakkor megjelenítettük a változók értékeit a töréspont helyein (6. és 9. sorszám).

Ezért az egyedi hibakeresőnk készen áll.

5.1. StepRequest

A hibakereséshez meg kell adni a kódot, és ellenőrizni kell a változók állapotát a következő lépéseknél. Ezért létrehozunk egy lépéskérést a törésponton.

Miközben létrehozta a StepRequest, meg kell adnunk a lépés méretét és mélységét. Meghatározzuk STEP_LINE és ÁTLÉP illetőleg.

Írjunk egy módszert a lépéskérés engedélyezésére.

Az egyszerűség kedvéért kezdjük az utolsó töréspontot (9. sorszám):

public void enableStepRequest (VirtualMachine vm, BreakpointEvent event) {// engedélyezi az utolsó töréspont lépéskérését, ha (event.location (). toString (). tartalmazza (debugClass.getName () + ":" + breakPointLines [breakPointLines.length- 1])) {StepRequest stepRequest = vm.eventRequestManager () .createStepRequest (event.thread (), StepRequest.STEP_LINE, StepRequest.STEP_OVER); stepRequest.enable (); }}

Most frissíthetjük a fő- módszere JDIExampleDebugger, a lépéskérés engedélyezéséhez, amikor a BreakPointEvent:

if (a BreakpointEvent esemény példánya) {debuggerInstance.enableStepRequest (vm, (BreakpointEvent) esemény); }

5.2. StepEvent

Hasonló a BreakPointEvent, a változókat a StepEvent.

Frissítsük a fő- módszer ennek megfelelően:

if (a StepEvent esemény példánya) {debuggerInstance.displayVariables ((StepEvent) esemény); }

Végül végrehajtjuk a hibakeresőt, hogy lássuk a változók állapotát, miközben belépünk a kódba:

Változók a com.baeldung.jdi.JDIExampleDebuggee címen: 6> args = a java.lang.String [0] (id = 93) példánya. A com.baeldung.jdi.JDIExampleDebuggee: 9> args = java.lang.String példányai [0] (id = 93) jpda = "Java Platform Debugger Architecture" változók a com.baeldung.jdi.JDIExampleDebuggee címen: 10> args = a java.lang.String példánya [0] (id = 93) jpda = "Java platform Hibakereső architektúra "jdi =" Java hibakeresési felület "Változók a com.baeldung.jdi.JDIExampleDebuggee címen: 11> args = java.lang.String [0] (id = 93) jpda =" Java platform hibakereső architektúra "jdi =" Java hibakereső felület "text =" Ma a Java Debug Interface "változókba merülünk át: com.baeldung.jdi.JDIExampleDebuggee: 12> args = java.lang.String [0] (id = 93) jpda =" változók Java Platform Debugger Architecture "jdi =" Java Debug Interface "text =" Ma belemerülünk a Java Debug Interface-be "A virtuális gép nincs csatlakoztatva.

Ha összehasonlítjuk a kimenetet, rájövünk, hogy a hibakereső belépett a 9. sorból, és minden további lépésben megjeleníti a változókat.

6. Olvassa el a Végrehajtás kimenet című részt

Ezt észrevehetjük println nyilatkozatai JDIExampleDuguggee osztály nem volt része a hibakereső kimenetnek.

A JDI dokumentációja szerint, ha a virtuális gépet elindítjuk LaunchingConnector, kimenetét és hibafolyamait a Folyamat tárgy.

Ezért tegyük hozzá a végül záradékunk fő- módszer:

végül {InputStreamReader olvasó = new InputStreamReader (vm.process (). getInputStream ()); OutputStreamWriter író = új OutputStreamWriter (System.out); char [] buf = új char [512]; olvasó.olvasott (buf); író.írni (buf); író.öblítés (); }

Most a hibakereső program végrehajtása hozzáadja a println nyilatkozatok a JDIExampleDuguggee osztály a hibakereső kimenethez:

Üdvözlet mindenkinek, Üdvözöljük a Java Platform Debugger Architecture-ben!

7. Következtetés

Ebben a cikkben feltártuk a Java Debug Interface (JDI) API-t, amely a Java Platform Debugger Architecture (JPDA) alatt érhető el.

Útközben létrehoztunk egy egyedi hibakeresőt, felhasználva a JDI által biztosított praktikus felületeket. Ugyanakkor a hibakeresőhöz léptető képességet is adtunk.

Mivel ez csak a JDI bevezetése volt, javasoljuk, hogy nézze meg a JDI API alatt elérhető egyéb interfészek megvalósítását.

Szokás szerint az összes kód implementáció elérhető a GitHubon.