Frage

Nur aus Neugier, gibt es (stable) Open-Source-Projekte für Runtime-Java-Code-Generierung andere als cglib? Und warum sollte ich sie verwenden?

War es hilfreich?

Lösung

ASM

CGLIB und fast alle anderen Bibliotheken sind auf der Oberseite des ASM gebaut, die sich auf einem sehr niedrigen Niveau wirkt. Dies ist ein Show-Stopper für die meisten Menschen, wie Sie den Byte-Code und ein wenig von der JVMs müssen verstehen, es richtig zu verwenden. Aber ASM Mastering ist sicherlich sehr interessant. Beachten Sie jedoch, dass es zwar eine groß ASM 4 Führung kann in einem Teil der API die javadoc Dokumentation sehr präzise sein, wenn sie überhaupt vorhanden ist, aber es verbessert wird. Es folgt eng JVM-Versionen neue Features zu unterstützen.

Wenn Sie jedoch die volle Kontrolle benötigen, ASM ist die Waffe der Wahl.

Dieses Projekt sieht regelmäßige Updates; zum Zeitpunkt dieser Bearbeitungsversion 5.0.4 wurde am 15. Mai 2015 veröffentlicht.

Byte Buddy

Byte Buddy ist eine ziemlich neue Bibliothek, sondern bietet jede Funktionalität, dass CGLIB oder Javassist bietet und vieles mehr. Byte Buddy vollständig angepasst nach unten in der Byte-Code-Ebene werden kann, und kommt mit einer ausdrucksdomänenspezifische Sprache, die für sehr lesbaren Code ermöglicht.

  • Es unterstützt alle JVM-Bytecode-Versionen, einschließlich Java 8 semantische Änderungen einiger OP-Codes in Bezug auf Standardmethoden.
  • ByteBuddy scheint nicht von den Nachteilen andere Bibliotheken zu leiden haben
  • In hohem Maße konfigurierbar
  • Sehr schnell ( Benchmark Code )
  • Geben Sie sicher fließend API
  • Geben Sie sichere Rückrufe

      

    Javassist Ratschläge oder benutzerdefinierter Instrumentationscode basiert auf Code in einer Ebene String somit Check eingeben und Debuggen ist unmöglich, in diesem Code, während ByteBuddy diejenigen mit reinem Java zu schreiben erlaubt erzwingt daher Typprüfungen und ermöglicht das Debuggen.

  • Annotation angetrieben (flexibel)

      

    Der Benutzer Rückruf konfiguriert werden kann mit Anmerkungen erlauben die gewünschten Parameter in dem Rückruf zu erhalten.

  • Erhältlich als Agent

      

    Der raffinierte Agent Builder ByteBuddy ermöglicht als reines Mittel verwendet werden oder als Mittel zu befestigen. Es ermöglicht verschiedene Art

  • Sehr gut dokumentiert
  • Viel Beispiel
  • Sauberer Code, ~ 94% Testabdeckung
  • Android DEX Unterstützung

Der größte Nachteil vielleicht würde die API ist ein bisschen ausführliche für einen Anfänger, aber es wird als eine Opt-in-API als Proxy Generation DSL förmig ausgebildet; es gibt keine Magie oder fragwürdige Vorgaben. Wenn Byte-Code-Manipulation ist es wahrscheinlich die sicherste und die vernünftigste Wahl. Auch mit mehreren Beispielen und einem großen Tutorial ist dies kein wirkliches Problem.

Im Oktober 2015 diese Projekte erhielten den Oracle Dukes Choice Award . Zu dieser Zeit erreichte sie nur die 1.0.0 Meilenstein , das ist schon eine Leistung.

Beachten Sie, dass ersetzt CGLIB von Byte Buddy in Version 2.1.0.

Javassist

Die javadoc von Javassist ist viel besser als die von CGLIB. Das Klasse-Engineering-API ist in Ordnung, aber Javassist ist auch nicht perfekt. Insbesondere die die ProxyFactory das Äquivalent der Enhancer des CGLIB ist leiden unter einigen Nachteilen zu, um nur einige aufzuzählen:

  • Bridge-Methode wird nicht vollständig unterstützt (dh derjenige, der für die kovarianten Rückgabetypen erzeugt werden)
  • ClassloaderProvider ist ein statisches Feld statt, dann ist es auf alle Fälle im gleichen Klassenlader gilt
  • Benutzerdefinierte Namensgebung willkommen gewesen sein könnte (mit Kontrollen für signierte Gläser)
  • Es gibt keinen Erweiterungspunkt und fast alle Methoden von Interesse sind privat, was mühsam ist, wenn wir ein bestimmtes Verhalten ändern mögen
  • Während Javassist bieten Unterstützung für Annotation in Klassen Attribute, werden sie nicht in ProxyFactory unterstützt.

Auf dem Aspekt orientierte Seite kann ein Code in einem Proxy injizieren, aber dieser Ansatz in Javassist begrenzt ist und ein wenig fehleranfällig:

  • Aspekt Code wird in einem einfachen Java String geschrieben, das ist zusammengestellt in Opcodes
  • keine Typprüfung
  • keine Generika
  • kein Lambda
  • keine auto- (un) Boxen

Auch ist Javassist anerkannt als CGLIB langsamer. Dies ist vor allem wegen seiner Annäherung von Klassendateien zu lesen, anstatt zu lesen geladene Klassen wie CGLIB tut. Und die Implementierung selbst ist hart, fair zu sein zu lesen; wenn man Änderungen vornehmen im Javassist Code erfordert es gibt viele Chancen, etwas zu brechen.

Javassist von Inaktivität litt auch, ihren Umzug zu Github circa 2013 scheint haben sich bewährt, da sie regelmäßig Commits und Pull-Anforderungen aus der Community zeigt.

stehen diese Einschränkungen noch in der Version 3.17.1. Version wurde auf Version 3.20.0 gestoßen worden, doch scheint es Javassist noch mit Java 8 Unterstützung Fragen haben.

JiteScript

JiteScript scheint wie ein neues Stück schön DSL für ASM Gestaltung auf, wird dies auf der Grundlage der neuesten ASM-Release (4.0). Der Code sieht sauber.

Aber ist das Projekt noch in seinem frühen Alter so API / Verhalten ändern kann, sowie die Dokumentation ist schrecklich. Und aktualisiert knapp, wenn nicht aufgegeben.

Proxetta

Dies ist ein ziemlich neues Tool bietet aber die bei weitem beste Mensch API. Es ermöglicht für verschiedene Arten von Proxies wie Unterklasse Proxies (cglib Ansatz) oder Weben oder eine Delegation.

Obwohl dies eine eher selten ist, gibt es keine Informationen, wenn es gut funktioniert. Es gibt so viele Ecke Fall zu befassen sich mit, wenn sie mit Bytecode zu tun.

AspectJ

AspectJ ist ein sehr mächtiges Werkzeug für aspektorientierte Programmierung (nur). AspectJ manipuliert Byte-Code erreichen ihre Ziele, so dass Sie damit Ihre Ziele zu erreichen könnten fähig sein. Dies erfordert jedoch eine Manipulation zur Compile-Zeit; Frühlingsangebot Weberei zur Ladezeit über einen Agenten seit Version 2.5 4.1.x .

CGLIB

Ein Wort über CGLIB die aktualisiert wurde, da diese Frage gestellt wurde.

CGLIB ist recht schnell, es ist eines der Hauptgrund, warum es immer noch rund ist, zusammen mit der Tatsache, dass CGLIB arbeitete fast besser als alle Alternativen bisher (2014-2015).

Im Allgemeinen Bibliotheken sprechen, die die Überschreibungs von Klassen zur Laufzeit müssen vermeiden Läden alle Typen, bevor die entsprechende Klasse ermöglichen wird neu geschrieben. Daher können sie nicht die Verwendung des Java-Reflection-API machen, die erfordert, dass jede Art der Reflexion verwendet wird, geladen. Stattdessen müssen sie die Klassendateien über IO lesen (das ist ein leistungsBrecher). Dies macht zum Beispiel Javassist oder Proxetta deutlich langsamer als CGLIB, die einfach die Methoden über das Reflection-API liest und überschreibt sie.

jedoch CGLIB ist nicht mehr aktiv weiterentwickelt. Es gab Neue Releases aber diese Änderungen wurden als unbedeutend von vielen und die meisten Menschen aktualisieren hat nie 3 auf Version gesehen, seit CGLIB einige schwere Fehler in dem letzten Releases was wirklich Vertrauen nicht aufbauen. 3.1 Version viele der Leiden der Version 3.0 behoben (seit Version 4.0.3 Spring-Framework neu verpackt Version 3.1 )

Auch die CGLIB Quellcode ist von eher schlechte Qualität , so dass wir das CGLIB Projekt keine neuen Entwickler sehen verbinden. überzeugen Sie einen Eindruck von CGLIB der active, ihre Mailingliste .

Beachten Sie, dass im Anschluss an einen Satz auf der guice Mailingliste ist CGLIB jetzt auf github zu ermöglichen die Gemeinschaft besser zu helfen, das Projekt scheint es (mehr Commits und Pull-Anforderungen, ci, aktualisiert maven) zu arbeiten, doch die meisten Bedenken noch bleiben.

Zu diesem Zeitpunkt gibt arbeiten an Version 3.2.0, und sie konzentrieren sich Anstrengungen auf Java 8, aber bisher Benutzer, dass Java-8-Unterstützung wollen, müssen Tricks bei der Erstellung verwenden. Aber der Fortschritt ist sehr langsam.

Und CGLIB wird noch bekannt für PermGen Speicherverlust geplagt werden. Aber auch andere Projekte können schon seit so vielen Jahren nicht gewesen Kampf getestet.

Compile Zeit Annotation Verarbeitung

Diese nicht-Laufzeit ist natürlich, sondern ist ein wichtiger Teil des Ökosystems und die meisten Codegenerierung Nutzung nicht Runtime Erstellung benötigen.

Dies begann mit Java 5, die mit dem separaten Kommandozeilen-Tool zur Prozess Anmerkungen kamen. apt, und ausgehend von Java 6 Anmerkung Verarbeitung wird in die Java-Compiler integriert

Zu einem bestimmten Zeitpunkt Sie explizit den Prozessor übergeben erforderlich waren, jetzt mit dem ServiceLoader Ansatz (nur diese Datei META-INF/services/javax.annotation.processing.Processor in das Gefäß hinzufügen) die Compiler automatisch den Annotation-Prozessor erkennen können.

Dieses ca.oach bei der Codegenerierung hat Nachteile zu es erfordert eine Menge Arbeit und das Verständnis der Sprache Java nicht Bytecode. Diese API ist ein wenig umständlich, und wie man in den Compiler eines Plugin mit äußerster Sorgfalt muss die stabilsten und benutzerfreundliche Fehlermeldung diesen Code zu machen.

Der größte Vorteil hier ist, dass es eine andere Abhängigkeit zur Laufzeit vermeidet, können Sie Permgen Speicherverlust vermeiden. Und man hat die volle Kontrolle über den generierten Code.

Fazit

2002 CGLIB einen neuen Standard definiert Bytecode mit Leichtigkeit zu manipulieren. Viele Werkzeuge und Methoden (CI, Abdeckung, TDD, etc.) haben wir waren heute nicht verfügbar oder nicht zu dieser Zeit reifen. CGLIB verwaltet seit mehr als einem Jahrzehnt relevant sein; Das ist eine ziemlich anständige Leistung. Es war schnell und mit einem einfachen API zu verwenden, als OP-Codes direkt zu manipulieren.

Es definiert neuen Standard in Bezug auf die Codegenerierung, aber heutzutage ist es nicht mehr, weil Umwelt und Anforderungen geändert haben, so die Standards und Ziele.

Die JVM verändert und wird sich in den letzten und zukünftigen Java (7/8/9/10) Versionen (invokedynamic Standardmethoden, Werttypen, etc.) ändern. ASM aktualisiert seine API und Interna regelmäßig um diese Änderungen zu folgen, aber CGLIB und andere haben noch sie zu nutzen.

Während Anmerkungsverarbeitung Traktion bekommen, es ist nicht so flexibel wie Runtime Generation.

Ab 2015 Byte Buddy - , während ziemlich neu auf der Szene - bietet die überzeugendsten Verkauf Punkte für die Laufzeit Generation. Eine ordentliche Update-Rate, und der Autor hat eine intime Kenntnis der Java-Bytecode-Interna.

Andere Tipps

Javassist .

Wenn Sie Proxies vornehmen müssen, werfen Sie einen Blick auf commons-Proxy - es verwendet sowohl CGLIB und Javassit.

Ich ziehe es roh ASM , das glaube ich sowieso von cglib verwendet wird. Es ist niedriges Niveau, aber die Dokumentation ist brilliant , und sobald man sich daran gewöhnen, werden Sie fliegen werden.

Ihre zweite Frage zu beantworten, sollten Sie die Codegenerierung verwenden, wenn die Reflexion und dynamische Proxys beginnen etwas zusammengeschustert zu fühlen, und Sie benötigen eine absolut solide Lösung. In der Vergangenheit habe ich sogar einen Code-Generierung für Schritt in den Build-Prozess in Eclipse, effektiv zu geben mir Kompilierung Berichterstattung über allem und alles gegeben.

Ich denke, es sinnvoller ist, zu verwenden Javassist statt cglib. Z.B. javasist arbeitet perfekt mit signierten Gläser im Gegensatz zu cglib. Außerdem, wie großartig wie Hibernate Projekt entschied mit cglib für Javassist zu stoppen.

CGLIB wurde entwickelt und mehr als zehn Jahre in AOP und ORM Ära umgesetzt. Derzeit sehe ich keinen Grund, es zu benutzen, und ich habe nicht diese Bibliothek pflegen mehr (außer Bug-Fixes für meine Legacy-Anwendungen). Eigentlich alle CGLIB Anwendungsfälle habe ich je gesehen habe sind anti-Muster in der modernen Programmierung. Es sollte trivial sein, die gleiche Funktionalität über jede JVM Skriptsprache zu implementieren z.B. groovy.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top