2009-06-18 4 views
58

Est-il possible d'ajouter un fichier (pas nécessairement un fichier jar) à java classpath lors de l'exécution. Plus précisément, le fichier est déjà présent dans le classpath, ce que je veux, c'est si je peux ajouter une copie modifiée de ce fichier au classpath.Ajout de fichiers au chemin de classe java au moment de l'exécution

Merci,

+0

Est-il e un moyen de supprimer un fichier jar? Ou le remplacer par une version plus récente? – dmarrazzo

Répondre

0

oui, vous pouvez. il devra être dans sa structure de paquet dans un répertoire séparé du reste de votre code compilé si vous voulez l'isoler. vous devrez ensuite placer son répertoire de base à l'avant du classpath sur la ligne de commande.

0

Oui Je crois que c'est possible mais vous devrez peut-être implémenter votre propre classloader. Je ne l'ai jamais fait mais c'est le chemin que je regarderais probablement.

5

Vous pouvez essayer java.net.URLClassloader avec l'url du dossier/jar où réside votre classe mise à jour et l'utiliser à la place du classloader par défaut lors de la création d'un nouveau thread.

37

Vous pouvez uniquement ajouter des dossiers ou des fichiers JAR à un chargeur de classe. Donc, si vous avez un seul fichier de classe, vous devez d'abord le placer dans la structure de dossier appropriée.

Here est un hack plutôt laid qui ajoute à la SystemClassLoader lors de l'exécution:

import java.io.IOException; 
import java.io.File; 
import java.net.URLClassLoader; 
import java.net.URL; 
import java.lang.reflect.Method; 

public class ClassPathHacker { 

private static final Class[] parameters = new Class[]{URL.class}; 

public static void addFile(String s) throws IOException { 
    File f = new File(s); 
    addFile(f); 
}//end method 

public static void addFile(File f) throws IOException { 
    addURL(f.toURL()); 
}//end method 


public static void addURL(URL u) throws IOException { 

    URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class sysclass = URLClassLoader.class; 

    try { 
    Method method = sysclass.getDeclaredMethod("addURL", parameters); 
    method.setAccessible(true); 
    method.invoke(sysloader, new Object[]{u}); 
    } catch (Throwable t) { 
    t.printStackTrace(); 
    throw new IOException("Error, could not add URL to system classloader"); 
    }//end try catch 

    }//end method 

}//end class 

La réflexion est nécessaire pour accéder à la méthode protégée addURL. Cela pourrait échouer s'il y a un SecurityManager.

+0

Merci pour la réponse les gars, je suppose que nous pouvons également ajouter un fichier simple (pas une classe ou un bocal, etc ...) dans le classpath, mais comment savoir lequel serait pris (le dernier ajout le classpath ou l'ancien fichier) –

+0

Ah, c'est un problème. Une grande partie de ceci est dépendante de l'implémentation, donc vous ne devriez vraiment pas avoir de classes (ou d'autres ressources) avec le même nom dans le même chargeur de classes. – Thilo

+0

Si vous les placez dans des chargeurs de classe distincts, il existe une spécification. En général, le classloader parent prend de la précision, pour les webapps c'est parfois l'inverse (mais toujours bien défini). Le bootloader vient toujours en premier. – Thilo

32

Essayez-le pour la taille.

private static void addSoftwareLibrary(File file) throws Exception { 
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); 
    method.setAccessible(true); 
    method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()}); 
} 

Cela modifie le chargeur de classe système pour inclure le fichier de bibliothèque donné. C'est assez moche, mais ça marche.

+0

Grande réponse.Je voudrais cependant l'éditer un peu, en utilisant des varargs pour le garder encore plus simple. –

12

La façon dont je l'ai fait est en utilisant ma propre classe chargeur

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
DynamicURLClassLoader dynalLoader = new DynamicURLClassLoader(urlClassLoader); 

Et créer la classe suivante:

public class DynamicURLClassLoader extends URLClassLoader{ 

public DynamicURLClassLoader(URLClassLoader classLoader) { 
    super(classLoader.getURLs()); 

} 

@Override 
public void addURL(URL url) { 
    super.addURL(url); 
} 

} 

Travaux sans réflexion

+0

Cette solution m'a semblé bonne, mais cela ne fonctionne pas (peut-être parce que je suis dans une application web Tomcat?). Je reçois une erreur "class not found" lorsque j'essaie d'appeler une méthode d'une classe contenue dans le fichier JAR chargé dynamique. Les autres solutions fonctionnent, même dans une application Web. – toni07

+0

Cela ne fonctionne pas puisque vous créez un nouveau classloader, les autres chargeurs de classe n'accéderont toujours pas au fichier que vous avez ajouté à ce classloader – cinqS

-2

Ma solution:

File jarToAdd = new File("/path/to/file"); 

new URLClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs()) { 
    @Override 
    public void addURL(URL url) { 
     super.addURL(url); 
    } 
}.addURL(jarToAdd.toURI().toURL()); 
+1

Veuillez expliquer ce que votre code fait (__dans la réponse elle-même, pas les commentaires__) en plus de le fournir . –

+0

Cela ne fonctionne pas car la méthode 'addURL' dans' URLClassLoader' est 'protected'. Mais vous pouvez écrire votre propre URLClassLoader qui réécrit la méthode et le modificateur devrait être accessible. – cinqS

Questions connexes