web-dev-qa-db-fra.com

Java: Laquelle des multiples ressources de la JVM classpath prend?

Si j'ai plusieurs fichiers du même nom sur classpath (par exemple, j'ai plusieurs .jar avec log4j.properties), quelles sont les règles que la JVM suit pour en choisir une?

47
Ondra Žižka

Il est spécifié par l'ordre dans lequel les ressources (c'est-à-dire généralement les fichiers jar) sont spécifiées à l'aide de -classpath option. Les ressources "antérieures" sur le chemin de classe ont priorité sur les ressources spécifiées après elles. Cela peut également être défini dans le fichier manifeste de votre application et vous n'avez pas besoin de fournir -classpath option. Vous voudrez peut-être vérifier ces articles sur la façon de travailler avec les fichiers manifestes.

La description exhaustive de "comment les classes sont trouvées" peut être trouvée ici , où la section sur JAR-class-path Classes décrit la logique de recherche des fichiers JAR.

51
mouser

Le ClassLoader détermine où se trouvera une ressource (extrait de ClassLoader JavaDoc):

La classe ClassLoader utilise un modèle de délégation pour rechercher des classes et des ressources. Chaque instance de ClassLoader a un chargeur de classe parent associé. Lorsqu'on lui demande de trouver une classe ou une ressource, une instance de ClassLoader délègue la recherche de la classe ou de la ressource à son chargeur de classe parent avant d'essayer de trouver la classe ou la ressource elle-même. Le chargeur de classe intégré de la machine virtuelle, appelé "chargeur de classe bootstrap", n'a pas lui-même de parent mais peut servir de parent d'une instance de ClassLoader.

Donc, partout où dans votre code Class # getResource ou Class # getResourceAsStream est appelé, cela se produit (tiré de Class.Java)

public Java.net.URL getResource(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResource(name);
    }
    return cl.getResource(name);
}

ClassLoader.Java:

public URL getResource(String name) {
    URL url;
    if (parent != null) {
        url = parent.getResource(name);
    } else {
        url = getBootstrapResource(name);
    }
    if (url == null) {
        url = findResource(name);
    }
    return url;
}

où ClassLoader # findResource doit en fait être remplacé par l'implémentation de ClassLoader. Cela implique que le comportement est différent sur un serveur d'applications, un Tomcat ou si vous exécutez à partir d'un fichier jar, cela dépend des implémentations ClassLoader de l'environnement dans lequel vous vous trouvez actuellement.

Ici est un exemple que vous pouvez utiliser pour retracer ce qui se passe sous le capot dans votre cas particulier.

8
emboss

Je contribue un cas prouvé que si classpath est, disons, tous les pots dans un dossier, et que vous souhaitez hiérarchiser l'un (ou certains) d'entre eux, cela ne fonctionne pas:

Les fenêtres:

bin/prioritized.jar;bin/*

Linux:

bin/prioritized.jar:bin/*

Il semble que le premier chemin bin/Priority.jar soit ignoré simplement parce que le second avec un caractère générique l'inclut dans sa propre portée. C'est ce qui rompt efficacement l'ordre spécifié des chemins de classe.

Par conséquent, afin de prioriser plusieurs ressources (testées sur Java 10.0.1), vous devez les placer dans des étendues non chevauchantes et elles fonctionneront ensuite.

0
S-t-x