Domanda

Solo per curiosità, esistono progetti open source (stabili) per la generazione di codice Java runtime diversi da CGlib?E perché dovrei usarli?

È stato utile?

Soluzione

ASM

CGLIB e quasi tutte le altre librerie sono costruite sopra ASM che a sua volta agisce a un livello molto basso.Questo è un punto fermo per la maggior parte delle persone poiché devi comprendere il codice byte e un po' del codice JVMS per usarlo correttamente.Ma padroneggiare l’ASM è sicuramente molto interessante.Si noti tuttavia che mentre esiste a Grande Guida ASM4, in alcune parti dell'API la documentazione javadoc può essere molto concisa se è presente, ma è in fase di miglioramento.Segue da vicino le versioni JVM per supportare le nuove funzionalità.

Tuttavia, se hai bisogno del pieno controllo, l'ASM è la tua arma preferita.

Questo progetto vede aggiornamenti regolari;al momento di questa modifica è stata rilasciata la versione 5.0.4 il 15 maggio 2015.

Byte amico

Byte Buddy è una libreria piuttosto nuova ma fornisce tutte le funzionalità fornite da CGLIB o Javassist e molto altro ancora.Byte Buddy può essere completamente personalizzato fino al livello del codice byte e viene fornito con un linguaggio espressivo specifico del dominio che consente un codice molto leggibile.

  • Supporta tutte le versioni del bytecode JVM, incluse le modifiche semantiche di Java 8 di alcuni codici operativi relativi ai metodi predefiniti.
  • ByteBuddy non sembra soffrire degli svantaggi di altre librerie
  • Altamente configurabile
  • Abbastanza veloce (segno di riferimento codice)
  • Digita l'API Safe Fluent
  • Digita richiamate sicure

    I consigli Javassist o il codice di strumentazione personalizzato si basano su un codice semplice String quindi il controllo del tipo e il debugging sono impossibili all'interno di questo codice, mentre ByteBuddy consente di scriverli con Java puro, quindi impone i controlli del tipo e consente il debug.

  • Guidato dalle annotazioni (flessibile)

    Le richiamate dell'utente possono essere configurate con annotazioni che consentono di ricevere i parametri desiderati nella richiamata.

  • Disponibile come agente

    L'ingegnoso generatore di agenti consente di utilizzare ByteBuddy come agente puro o come agente di collegamento.Permette diversi tipi

  • Molto ben documentato
  • Molti esempi
  • Codice pulito, copertura del test del 94% circa
  • Supporto AndroidDEX

Lo svantaggio principale forse è che l'API è un po' prolissa per un principiante, ma è progettata come un'API opt-in modellata come una DSL di generazione proxy;non ci sono impostazioni predefinite magiche o discutibili.Quando si manipola il codice byte è probabilmente la scelta più sicura e ragionevole.Inoltre con più esempi e un grande tutorial questo non è un vero problema.

Nell'ottobre 2015 questo progetto ha ricevuto il premio Premio scelto da Oracle Duke.In questo momento ha appena raggiunto il Traguardo 1.0.0, il che è un bel risultato.

Notare che ha sostituito CGLIB di Byte Buddy nella versione 2.1.0.

Javassist

Il javadoc di Javassist è decisamente migliore di quello di CGLIB.L'API di ingegneria delle classi è OK, ma neanche Javassist è perfetto.In particolare, il ProxyFactory che è l'equivalente del CGLIB Enhancer presentano anche alcuni inconvenienti, solo per elencarne alcuni:

  • Il metodo Bridge non è completamente supportato (ovvero quello generato per i tipi restituiti covarianti)
  • ClassloaderProvider è invece un campo statico, quindi si applica a tutte le istanze all'interno dello stesso classloader
  • La denominazione personalizzata avrebbe potuto essere gradita (con assegni per i barattoli firmati)
  • Non esiste un punto di estensione e quasi tutti i metodi di interesse sono privati, il che è scomodo se vogliamo cambiare qualche comportamento
  • Sebbene Javassist offra supporto per gli attributi di annotazione nelle classi, non sono supportati in ProxyFactory.

Per quanto riguarda l'aspetto orientato, è possibile inserire codice in un proxy, ma questo approccio in Javassist è limitato e un po' soggetto a errori:

  • il codice aspetto è scritto in una semplice stringa Java compilato nei codici operativi
  • nessun controllo del tipo
  • niente generici
  • niente lambda
  • nessun auto-(un)boxing

Anche Javassist è riconosciuto come più lento di Cglib.Ciò è dovuto principalmente al suo approccio di lettura dei file di classe invece di leggere le classi caricate come fa CGLIB.E il implementazione di per sé è difficile da leggere per essere onesti;se è necessario apportare modifiche al codice Javassist ci sono molte possibilità che si rompa qualcosa.

Anche Javassist ha sofferto di inattività, il loro passaggio a github intorno al 2013 sembra essersi dimostrato utile in quanto mostra commit regolari e richieste pull dalla comunità.

Queste limitazioni sono ancora presenti nella versione 3.17.1.La versione è stata aggiornata alla versione 3.20.0, ma sembra che Javassist possa ancora avere problemi con il supporto Java 8.

JiteScript

JiteScript sembra un nuovo pezzo di DSL ben modellato per ASM, basato sull'ultima versione ASM (4.0).Il codice sembra pulito.

Ma il progetto è ancora in fase iniziale, quindi l'API/il comportamento possono cambiare, inoltre la documentazione è pessima.E gli aggiornamenti scarsi se non abbandonati.

Prossetta

Questo è uno strumento piuttosto nuovo ma offre di gran lunga il meglio umano API.Consente diversi tipi di proxy come proxy di sottoclasse (approccio CGlib) o tessitura o delega.

Anche se questo è piuttosto raro, non esistono informazioni sul fatto che funzioni bene.Ci sono così tanti casi limite da affrontare quando si ha a che fare con il bytecode.

AspettoJ

AspectJ è uno strumento molto potente per programmazione orientata agli aspetti (soltanto).AspectJ manipola il codice byte per raggiungere i suoi obiettivi in ​​modo tale che tu possa essere in grado di raggiungere i tuoi obiettivi con esso.Tuttavia, ciò richiede la manipolazione in fase di compilazione;offerta primaverile tessitura al momento del caricamento tramite un agente a partire dalla versione 2.5, 4.1.x.

CGLIB

Una parola su CGLIB che è stata aggiornata da quando è stata posta quella domanda.

CGLIB è abbastanza veloce, ed è uno dei motivi principali per cui è ancora in circolazione, insieme al fatto che CGLIB ha funzionato quasi meglio di qualsiasi alternativa fino ad ora (2014-2015).

In generale le librerie che consentono la riscrittura delle classi in fase di esecuzione devono evitare di caricare qualsiasi tipo prima che la classe corrispondente venga riscritta.Pertanto, non possono utilizzare l'API di riflessione Java che richiede il caricamento di qualsiasi tipo utilizzato nella riflessione.Devono invece leggere i file di classe tramite IO (che compromette le prestazioni).Ciò rende, ad esempio, Javassist o Proxetta significativamente più lenti di Cglib che legge semplicemente i metodi tramite l'API di riflessione e li sovrascrive.

Tuttavia, CGLIB non è più in fase di sviluppo attivo.Ci sono state versioni recenti ma questi cambiamenti sono stati visti come insignificanti da molti e la maggior parte delle persone non ha mai aggiornato alla versione 3 da quando CGLIB ha introdotto alcuni bug gravi nelle ultime versioni ciò che non ha realmente rafforzato la fiducia. La versione 3.1 ha risolto molti dei problemi della versione 3.0 (dalla versione 4.0.3 Spring Framework riconfeziona versione 3.1).

Inoltre, il codice sorgente CGLIB è piuttosto scarsa qualità in modo tale che non vediamo nuovi sviluppatori unirsi al progetto CGLIB.Per un'idea dell'attività del CGLIB, vedere il loro lista di posta.

Si noti che dopo a proposta sulla mailing list di Guice, CGLIB è ora disponibile su github per consentire alla comunità di aiutare meglio il progetto, sembra che funzioni (commit multipli e richieste pull, ci, maven aggiornato), ma la maggior parte delle preoccupazioni rimangono ancora.

In questo momento stanno lavorando alla versione 3.2.0 e si stanno concentrando su Java 8, ma finora gli utenti che desiderano il supporto di Java 8 devono utilizzare trucchi in fase di compilazione.Ma i progressi sono molto lenti.

E CGLIB è ancora noto per essere afflitto dalla perdita di memoria di PermGen.Ma altri progetti potrebbero non essere stati messi alla prova per così tanti anni.

Elaborazione dell'annotazione del tempo di compilazione

Questo ovviamente non è runtime, ma è una parte importante dell'ecosistema e la maggior parte dell'utilizzo della generazione di codice non richiede la creazione di runtime.

Tutto è iniziato con Java 5 fornito con lo strumento da riga di comando separato per elaborare le annotazioni: apt, e a partire da Java 6 l'elaborazione delle annotazioni è integrata nel compilatore Java.

Ad un certo punto ti veniva richiesto di passare esplicitamente il processore, ora con il file ServiceLoader approccio (basta aggiungere questo file META-INF/services/javax.annotation.processing.Processor al jar) il compilatore può rilevare automaticamente il processore di annotazioni.

Questo approccio alla generazione del codice presenta anche degli svantaggi: richiede molto lavoro e comprensione del linguaggio Java e non del bytecode.Questa API è un po' macchinosa e, poiché è un plug-in nel compilatore, è necessario prestare la massima attenzione per rendere questo codice il messaggio di errore più resiliente e facile da usare.

Il vantaggio più grande qui è che evita un'altra dipendenza in fase di esecuzione, potresti evitare perdite di memoria permanenti.E si ha il pieno controllo sul codice generato.

Conclusione

In 2002 CGLIB ha definito un nuovo standard per manipolare facilmente il bytecode.Molti strumenti e metodologie (CI, copertura, TDD, ecc.) di cui disponiamo oggi non erano disponibili o non erano maturi in quel momento.CGLIB è riuscita ad essere rilevante per più di un decennio;è un risultato abbastanza decente.Era veloce e con un'API facile da usare rispetto alla manipolazione diretta dei codici operativi.

Ha definito nuovi standard per quanto riguarda la generazione del codice, ma oggi non lo è più perché l'ambiente e i requisiti sono cambiati, così come gli standard e gli obiettivi.

La JVM è cambiata e cambierà nelle versioni recenti e future di Java (7/8/9/10) (invokedynamic, metodi predefiniti, tipi di valore, ecc.).ASM ha aggiornato regolarmente la sua API e i suoi componenti interni per seguire questi cambiamenti, ma CGLIB e altri devono ancora utilizzarli.

Sebbene l'elaborazione delle annotazioni stia prendendo sempre più piede, non è flessibile come la generazione di runtime.

A partire dal 2015, Byte amicoanche se piuttosto nuovo sulla scena - offrire il più convincente vendita punti per la generazione del runtime.Una frequenza di aggiornamento decente e l'autore ha una conoscenza approfondita degli interni del byte code Java.

Altri suggerimenti

Javassist .

Se avete bisogno di fare i proxy, dare un'occhiata a commons-delega - utilizza sia CGLIB e Javassit.

ASM , che credo sia utilizzato da cglib comunque. E 'di basso livello, ma la documentazione è brillante , e una volta che ci si abitua ad esso sarete volare.

Per rispondere alla tua seconda domanda, è necessario utilizzare la generazione del codice, quando la vostra riflessione e proxy dinamici stanno cominciando a sentire un po 'messo insieme e avete bisogno di una soluzione solida roccia. In passato ho anche aggiunto un passo di generazione di codice nel processo di generazione in Eclipse, in modo efficace dandomi compilo segnalazione in tempo di tutto e di più.

Credo che sia più sensato usare Javassist invece di cglib. Per esempio. javasist funziona perfettamente con vasi firmati a differenza cglib. Inoltre, tale progetto grande come Hibernate ha deciso di smettere di usare cglib a favore di Javassist .

CGLIB è stato progettato e realizzato più di dieci anni fa in AOP e ORM epoca. Attualmente non vedo motivi per usarlo e non mi mantengo questa libreria più (ad eccezione di correzioni di bug per le mie applicazioni legacy). In realtà tutti CGLIB usano casi io abbia mai visto sono modelli anti-nella programmazione moderna. Dovrebbe essere banale per implementare la stessa funzionalità tramite qualsiasi linguaggio di scripting per esempio JVM Groovy.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top