2009-04-08 11 views
11

Sto scrivendo un programma server che viene utilizzato per eseguire unit test di un API (visualizzazione di un sacco di informazioni e di fornire l'accesso web per controllare /monitorare il tutto) ...Posso scaricare e ricaricare dinamicamente (altre versioni dello stesso) JAR?

Questa API è noto al server durante il periodo di compilazione e viene fornito come JAR .

Per poter confrontare tra i risultati di prova Unità di diverse versioni delle API (senza riavviare il server), io voglio essere in grado di scaricare la versione 'corrente' delle API, e per ricaricare uno più recente (o uno più vecchio).

Non voglio usare URLClassLoader e richiamare ogni singolo metodo per nome
(usando getDeclaredMethod("someMethod")),
perché il server pesantemente dipende dalla API e sarebbe complicato a 'wrap' ogni chiamata di metodo in modo così sporco.

Stavo pensando: Dal momento che tutte le interfacce di tutti versioni del JAR sono stesso, non potrei farlo in qualche modo a ricaricare un'altra versione del JAR (senza che per nome-invocazione?).

Nota: sto utilizzando l'ultima versione di Java SE (6) e Java EE (5).

Se si pensa, ciò che sto cercando di ottenere non è possibile, si prega di suggerire una "soluzione" o un concetto diverso.

+0

Vedi anche: http://stackoverflow.com/questions/148681/unloading-classes-in-java – sleske

risposta

7

penso che se si carica una classe utilizzando

Class.forName(clsname, init, classloader); 

(Javadoc qui) si ottiene un'istanza della classe fornita dalla data di caricamento classe. Tutto ciò che viene caricato a causa di quella classe verrà caricato anche tramite lo stesso classloader.

Fintanto che fai attenzione agli oggetti istanziati da questo punto in poi (per consentire GC), dovresti essere in grado di ricaricare diverse versioni. L'ho fatto una volta in precedenza con Java 1.3, ci sono voluti molti debugging, ma alla fine ho avuto un'applicazione "bootstrap" che ha caricato una classe Runnable per nome ed è stata in grado di eseguire un "soft-restart" istanziando un nuovo classloader contro un URL diverso e andare di nuovo.

-2

Probabilmente no. Il classloader Java in realtà non supporta il caricamento in fase di esecuzione; anche i classloader disponibili sono hack che usano un oggetto proxy.

1

OSGi è un framework che ti consentirà di farlo. JSR 277 the Java Module System è progettato per farlo anche io (penso). Non ho seguito il dibattito OSGi -vs- JSR 277, quindi non so se stanno cercando di metterli da parte.

Puoi lanciare da solo con i caricatori di classe, ma sarà meno "divertente".

0

Sì. L'ho visto fare in una conferenza NFJS.È il modo in cui cose come i contenitori web supportano la distribuzione a caldo di applicazioni e coinvolgono l'ambito dei caricatori di classe. Per realizzarlo è necessario creare un nuovo caricatore di classe e utilizzarlo per caricare la libreria in questione .. quindi lanciare il caricatore (o no) e crearne un altro quando si desidera ricaricare. Potrebbe anche essere necessario sovrascrivere il comportamento del programma di caricamento classi (ricordo qualcosa sui programmi di caricamento classe che ottengono le classi tramite il loro genitore prima per impostazione predefinita.) Inoltre, ricordo un avviso che gli oggetti creati da diversi programmi di caricamento classe sono non compatibile (non di lo stesso tipo) tra loro anche se il file .class è esattamente lo stesso.

Per me è principalmente deep magic. ;-)

4

È possibile modificare in modo programmatico il percorso di classe in modo da riflettere le modifiche JAR. Ecco come lo farei:

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
     Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); 
     m.setAccessible(true); 
     m.invoke(urlClassLoader, jarFile.toURI().toURL()); 
     String cp = System.getProperty("java.class.path"); 
     if (cp != null) { 
      cp += File.pathSeparatorChar + jarFile.getCanonicalPath(); 
     } else { 
      cp = jarFile.toURI().getPath(); 
     } 
     System.setProperty("java.class.path", cp); 

dove JarFile è la versione del vaso che si desidera utilizzare/sovrascrittura.

3

È possibile utilizzare il pacchetto opensource: JclLoader che aiuta a caricare diverse versioni dello stesso jar. Anche in uno dei nostri sistemi era necessario eseguire test.

Link: http://sourceforge.net/projects/jcloader/

+0

lo uso. Funziona, una nota: se vuoi ricaricare la classe dovresti farlo con una diversa istanza JarClassLoader, se la provi con lo stesso errore del classloader verrai generato, basta crearne un'altra. – odiszapc

+0

Ho provato molte soluzioni ... Posso confermare, questa è la soluzione più semplice e più elegante che ho trovato per il caricamento dinamico della classe. Questa dovrebbe essere la risposta accettata. – taylorcressy

Problemi correlati