Domanda

Ho un caricatore di classi personalizzato in modo che un'applicazione desktop possa iniziare in modo dinamico il caricamento di classi da un AppServer con cui devo parlare. Lo abbiamo fatto poiché la quantità di barattoli necessari per farlo è ridicola (se volessimo spedirli). Abbiamo anche problemi di versione se non cariciamo dinamicamente le classi in fase di esecuzione dalla libreria AppServer.

Ora, ho appena riscontrato un problema in cui ho bisogno di parlare con due diversi AppServer e ho scoperto che, a seconda delle classi caricate per prime, potrei interrompere male ... C'è un modo per forzare lo scarico della classe senza uccidere effettivamente la JVM?

Spero che abbia senso

È stato utile?

Soluzione

L'unico modo in cui una Classe può essere scaricata è se il Classloader utilizzato è la garbage collection. Ciò significa che i riferimenti a ogni singola classe e al classloader stesso devono seguire la strada del dodo.

Una possibile soluzione al problema è disporre di un Classloader per ogni file jar e di un Classloader per ciascuno degli AppServer che delegano il caricamento effettivo delle classi a specifici classloader Jar. In questo modo, puoi puntare a versioni diverse del file jar per ogni server App.

Questo non è banale, però. La piattaforma OSGi si impegna a fare proprio questo, poiché ogni bundle ha un caricatore di classi diverso e le dipendenze vengono risolte dalla piattaforma. Forse una buona soluzione sarebbe di darci un'occhiata.

Se non si desidera utilizzare OSGI, una possibile implementazione potrebbe essere quella di utilizzare un'istanza di classe JarClassloader per ogni file JAR.

E crea una nuova classe MultiClassloader che estende Classloader. Questa classe internamente avrebbe una matrice (o un elenco) di JarClassloader e nel metodo defineClass () ripeterebbe tutti i caricatori di classi interni fino a quando non verrà trovata una definizione o verrà generata una NoClassDefFoundException. È possibile fornire un paio di metodi di accesso per aggiungere nuovi JarClassloader alla classe. Esistono diverse possibili implementazioni in rete per un MultiClassLoader, quindi potrebbe non essere nemmeno necessario scriverne uno tuo.

Se installi un MultiClassloader per ogni connessione al server, in linea di principio è possibile che ogni server utilizzi una versione diversa della stessa classe.

Ho usato l'idea MultiClassloader in un progetto, in cui le classi che contenevano script definiti dall'utente dovevano essere caricate e scaricate dalla memoria e funzionava abbastanza bene.

Altri suggerimenti

Sì, ci sono modi per caricare le classi e "scaricare" " più tardi. Il trucco è implementare il proprio caricatore di classi che risiede tra il caricatore di classi di alto livello (il caricatore di classi di sistema) e i caricatori di classi dei server delle app e sperare che i caricatori di classi del server delle app deleghino il caricamento delle classi ai caricatori superiori .

Una classe è definita dal suo pacchetto, dal suo nome e dal caricatore di classi che ha caricato originariamente. Programmare un "proxy" classloader che è il primo che viene caricato all'avvio di JVM. Flusso di lavoro:

  • Il programma si avvia e la vera classe "quot" principale "viene caricata da questo classloader proxy.
  • Ogni classe che viene quindi normalmente caricata (ovvero non tramite un'altra implementazione del programma di caricamento classi che potrebbe interrompere la gerarchia) verrà delegata a questo programma di caricamento classe.
  • Il proxy classloader delega java.x e sun.x al classloader di sistema (questi non devono essere caricati attraverso un altro caricatore di classi diverso da il classloader di sistema).
  • Per ogni classe che è sostituibile, crea un'istanza di un classloader (che carica realmente la classe e non la delega al classloader principale) e caricalo attraverso questo.
  • Memorizza il pacchetto / nome delle classi come chiavi e il classloader come valori in una struttura di dati (es. Hashmap).
  • Ogni volta che il programma di caricamento classi proxy riceve una richiesta per una classe che è stata caricata in precedenza, restituisce la classe dal programma di caricamento classi memorizzato in precedenza.
  • Dovrebbe essere sufficiente individuare l'array di byte di una classe dal proprio caricatore di classi (o "eliminare" la coppia chiave / valore dalla struttura dei dati) e ricaricare la classe nel caso in cui si desideri modificarla.

Fatto proprio non dovrebbe venire un ClassCastException o LinkageError ecc.

Per ulteriori informazioni sulle gerarchie del caricatore di classi (sì, è esattamente quello che stai implementando qui; -) guarda " ; Programmazione Java basata su server " di Ted Neward - quel libro mi ha aiutato a implementare qualcosa di molto simile a quello che vuoi.

Ho scritto un programma di caricamento classi personalizzato, dal quale è possibile scaricare singole classi senza GCing il programma di caricamento classi. Caricatore di classi Jar

I classloader possono essere un problema complicato. In particolare, puoi riscontrare problemi se stai utilizzando più classloader e non hai le loro interazioni chiaramente e rigorosamente definite. Penso che per poter effettivamente scaricare una classe che stai andando devi rimuovere tutti i riferimenti a tutte le classi (e le loro istanze) che stai cercando di scaricare.

Molte persone che hanno bisogno di fare questo tipo di cose finiscono per usare OSGi . OSGi è davvero potente, sorprendentemente leggero e facile da usare,

Puoi scaricare ClassLoader ma non puoi scaricare classi specifiche. Più specificamente, non puoi scaricare le classi create in un ClassLoader che non è sotto il tuo controllo.

Se possibile, ti suggerisco di usare il tuo ClassLoader in modo da poter scaricare.

Le classi hanno un forte riferimento implicito alla loro istanza ClassLoader e viceversa. Sono rifiuti raccolti come con oggetti Java. Senza colpire l'interfaccia degli strumenti o simili, non è possibile rimuovere singole classi.

Come sempre è possibile ottenere perdite di memoria. Qualsiasi riferimento forte a una delle tue classi o al caricatore di classi perderà il tutto. Ciò si verifica con le implementazioni Sun di ThreadLocal, java.sql.DriverManager e java.beans, ad esempio.

Se stai guardando dal vivo se la classe di scarico ha funzionato in JConsole o qualcosa del genere, prova anche ad aggiungere java.lang.System.gc () alla fine della logica di scaricamento della classe. Attiva esplicitamente Garbage Collector.

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