© Excellent backgrounds/Shutterstock.com
Kolumne: Java-Trickkiste

Bytecode-Analyse im Eigenbau


Letzten Monat haben wir uns angesehen, wie man den Classpath scannen kann, ohne Klassen in die JVM zu laden und dann Reflection zu verwenden [1]. Jetzt gehen wir wie angekündigt einen Schritt weiter und analysieren Aufrufketten auf Basis des Bytecodes. Als Beispiel dafür, was damit möglich ist, erstellen wir ein Ranking der am häufigsten aufgerufenen Methoden und suchen die Methoden mit der größten inneren Komplexität heraus. Wie schon letzten Monat verwenden wir dazu die Bytecode-Bibliothek asm [2].

Video: Retro Gaming with Lambdas

Rückblick: Zusammensuchen von Klassen

Die Analyse des Bytecodes beruht auf dem Code zum Scannen des Classpath, den wir letzten Monat betrachtet haben. Deshalb hier eine kurze Wiederholung – wer den Code noch vor seinem inneren Auge hat, kann diesen Abschnitt getrost überspringen.

Der erste Schritt ist, alle JAR-Dateien bzw. Verzeichnisse zu finden, die Klassen des Systems enthalten. Dabei gehen wir davon aus, dass die gesamte Anwendung über einen einzigen URLClassLoader geladen wird, und holen uns von ihm und seinen Eltern-ClassLoadern die URLs (Listing 1).

Listing 1

public List<URL> getRootUrls () { List<URL> result = new ArrayList<> (); ClassLoader cl = Thread.currentThread().getContextClassLoader(); while (cl != null) { if (cl instanceof URLClassLoader) { URL[] urls = ((URLClassLoader) cl).getURLs(); result.addAll (Arrays.asList (urls)); } cl = cl.getParent(); } return result; }

Anschließend iterieren wir für jeden dieser URLs über alle enthaltenen Class-Dateien. Für Verzeichnisse steigen wir dazu rekursiv in die Unterverzeichnisse ab und betrachten in jedem Verzeichnis alle Dateien mit der Endung .class, während wir JAR-Dateien mit einem JARInputStream über die enthaltenen Dateien iterieren.

Dieser Code ist durchaus interessant, hat aber mit dem Analysieren des Bytecodes direkt nichts zu tun. Weil er gleichzeitig nicht ganz kurz ist, wiederhole ich ihn hier nicht und verweise auf [1] und die Dokumentation zu JARInputStream.

ClassVisitor: Infos zur Klasse

Wir öffnen dann für jede Class-Datei einen InputStream auf ihren rohen Inhalt und übergeben den an die Bibliothek asm – genauer gesagt eine Instanz von ClassReader – zum Einlesen. asm ist extrem auf Effizienz optimiert und arbeitet deshalb mit „Streaming“: Es liest eine Class-Datei einmal von vorne nach hinten ein, und man kann Callbacks registrieren für alles, was einen interessiert. Diese Callbacks heißen bei asm „Visitor“, und es gibt für verschiedene Bestandteile e...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang