2009-04-08 7 views
11

Je vous écris un programme serveur qui est utilisé pour exécuter des tests unitaires d'une API (afficher beaucoup d'informations et l'accès Web pour contrôler /surveiller la chose) ...Puis-je décharger et recharger dynamiquement (d'autres versions du même fichier JAR)?

Cette API est connu du serveur pendant la compilation et est fourni en tant que fichier JAR.

Pour pouvoir comparer entre les résultats des tests unitaires de versions différentes de l'API (sans redémarrer le serveur), je veux être en mesure de décharger la version « actuelle » de l'API, et de recharger un plus récent (ou un plus ancien).

Je ne veux pas utiliser URLClassLoader et invoquer chaque méthode par nom
(en utilisant getDeclaredMethod("someMethod")),
parce que le serveur dépend fortement de l'API et ce serait compliqué à « wrap » tous les appel de méthode de manière si sale.

Je pensais: Comme toutes les interfaces de toutes versions du JAR sont même, je ne pourrais pas le faire par une autre en quelque sorte rechargeant la version du JAR (sans que par nom invokation?).

Remarque: J'utilise les dernières versions Java SE (6) et Java EE (5).

Si vous pensez, ce que j'essaie de réaliser n'est pas possible, veuillez suggérer une «solution de contournement» ou un concept différent.

+0

Voir aussi: http://stackoverflow.com/questions/148681/unloading-classes-in-java – sleske

Répondre

7

Je pense que si vous chargez une classe à l'aide

Class.forName(clsname, init, classloader); 

(Javadoc ici), vous obtiendrez une instance de la classe fournie par le classloader donné. Tout ce qui est chargé à cause de cette classe sera également chargé via le même classloader.

Tant que vous êtes très prudent avec les objets instanciés à partir de ce point (pour permettre GC), vous devriez être capable de recharger différentes versions. Je l'ai déjà fait avec Java 1.3, il a fallu beaucoup de débogage, mais à la fin j'avais une application "bootstrap" qui chargeait une classe Runnable par son nom et était capable de "redémarrer" en instanciant un nouveau classloader URL différente et aller à nouveau.

-2

Probablement pas. Le classloader Java ne prend pas réellement en charge le chargement au moment de l'exécution. même les classloaders disponibles sont des hacks qui utilisent un objet proxy.

1

OSGi est un framework qui vous permettra de le faire. JSR 277 the Java Module System est conçu pour faire cela aussi (je pense). Je n'ai pas suivi le débat de l'OSGi -vs- JSR 277, donc je ne sais pas s'ils essaient de les évaluer du tout.

Vous pouvez rouler les vôtres avec des chargeurs de classe, mais ce sera moins amusant.

0

Oui. Je l'ai vu fait lors d'une conférence NFJS.C'est ainsi que des conteneurs Web prennent en charge le déploiement à chaud d'applications et impliquent de tirer parti de la portée des chargeurs de classe. Pour ce faire, vous devez créer un nouveau chargeur de classe et l'utiliser pour charger la librairie en question .. puis rejeter le chargeur (ou non) et en créer un autre lorsque vous voulez recharger. Vous devrez peut-être outrepasser le comportement du chargeur de classe (je me souviens de quelque chose à propos des chargeurs de classes qui reçoivent des classes via leur parent par défaut). Je me souviens aussi d'un avertissement que les objets créés par différents chargeurs de classes sont compatibles. le même type) les uns avec les autres même si le fichier .class est exactement le même. Mais c'est pour la plupart deep magic pour moi. ;-)

4

Vous pouvez modifier par programme votre chemin de classe pour refléter vos modifications JAR. Voici comment je le ferais:

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); 

JarFile est la version du pot que vous souhaitez utiliser/remplacer.

3

Vous pouvez utiliser le package opensource: JclLoader qui permet de charger différentes versions du même fichier. C'était également un besoin dans l'un de nos systèmes de faire des tests.

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

+0

Je l'utilise. Cela fonctionne, une note - si vous voulez recharger la classe vous devriez le faire avec une instance différente de JarClassLoader, si vous l'essayez avec la même erreur de classloader sera jeté, juste en créer un autre. – odiszapc

+0

J'ai essayé beaucoup de solutions ... Je peux confirmer, c'est la solution la plus élégante la plus simple que j'ai pu trouver pour le chargement dynamique de classe. Cela devrait vraiment être la réponse acceptée. – taylorcressy

Questions connexes