207 votes

Quelle est la différence entre Class.getResource() et ClassLoader.getResource() ?

Je me demande quelle est la différence entre Class.getResource() y ClassLoader.getResource() ?

edit : Je veux surtout savoir si une mise en cache est impliquée au niveau des fichiers/répertoires. Comme dans "les listes de répertoires sont-elles mises en cache dans la version Class ?"

AFAIK, les éléments suivants devraient essentiellement faire la même chose, mais ils ne le font pas :

getClass().getResource() 
getClass().getClassLoader().getResource()

J'ai découvert cela en manipulant un code de génération de rapports qui crée un nouveau fichier dans le dossier de l'utilisateur. WEB-INF/classes/ à partir d'un fichier existant dans ce répertoire. En utilisant la méthode de la classe, je pouvais trouver des fichiers qui étaient là lors du déploiement en utilisant getClass().getResource() mais lorsque j'ai essayé de récupérer le fichier nouvellement créé, j'ai reçu un objet nul. La navigation dans le répertoire montre clairement que le nouveau fichier est là. Les noms de fichiers ont été précédés d'une barre oblique comme dans "/myFile.txt".

El ClassLoader version de getResource() d'autre part a trouvé le fichier généré. D'après cette expérience, il semble qu'il y ait une sorte de mise en cache de la liste des répertoires. Ai-je raison, et si oui, où cela est-il documenté ?

De la Documents de l'API en Class.getResource()

Trouve une ressource avec un nom donné. Les règles pour recherche des ressources associées à une classe donnée sont implémentées par la classe chargeur de classe de la classe. Cette méthode délègue au chargeur de classe de cet objet chargeur de classe de cet objet. Si cet objet a été chargé par le chargeur de classe d'amorçage, la méthode délègue à ClassLoader.getSystemResource(java.lang.String).

Pour moi, cela signifie que "Class.getResource appelle en réalité la fonction getResource() de son propre chargeur de classe". Ce qui reviendrait à faire getClass().getClassLoader().getResource() . Mais ce n'est manifestement pas le cas. Quelqu'un pourrait-il m'éclairer sur cette question ?

265voto

Jon Skeet Points 692016

Class.getResource peut prendre un nom de ressource "relatif", qui est traité par rapport au paquetage de la classe. Vous pouvez également spécifier un nom de ressource "absolu" en utilisant un slash de tête. Les chemins des ressources du chargeur de classe sont toujours considérés comme absolus.

Les éléments suivants sont donc fondamentalement équivalents :

foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");

Et celles-ci aussi (mais elles sont différentes des précédentes) :

foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

0 votes

Bonne réponse avec des exemples clairs. Bien que le message visait en fait à obtenir des réponses à deux questions, je vois maintenant que la deuxième question est en quelque sorte cachée. Je ne sais pas si je dois mettre à jour le message pour refléter cela, mais ce que je voudrais savoir en second lieu est ceci (commentaire suivant) :

3 votes

Y a-t-il une sorte de mise en cache dans la version Class.getResource() ? Ce qui m'a amené à penser cela, c'est la génération de certains rapports Jasper : Nous utilisons getClass().getResource("/aDocument.jrxml") pour récupérer le fichier xml de jasper. Un fichier binaire jasper est ensuite produit dans le fichier même getClass().getResource("/aDocument.jasper") n'est pas capable de le trouver, bien qu'il puisse clairement trouver des documents au même niveau (le fichier d'entrée). C'est là que ClassLoader.getResource() s'est avéré utile, car il semble qu'il n'utilise pas la mise en cache de la liste des répertoires. Mais je ne trouve pas de documentation à ce sujet.

3 votes

@oligofren : Hmm... Je ne le ferais pas s'attendre à Class.getResource() pour y faire de la mise en cache...

25voto

Aaron Digulla Points 143830

Le premier appel effectue une recherche relative au .class tandis que la seconde recherche par rapport à la racine du classpath.

Pour déboguer ce genre de problème, j'imprime l'URL :

System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

3 votes

Je pense que "classloader Root" serait plus précis que "classpath Root" - juste pour être pointilleux.

4 votes

Les deux peuvent rechercher des "chemins absolus" si le nom du fichier est précédé de "/".

3 votes

Intéressant... Je me heurte à un cas où getClass().getResource("/someAbsPath") retourne une URL du type /path/to/mylib.jar!/someAbsPath et où getClass().getClassLoafer().getResource("/someAbsPath") retourne null... Donc "Root of classloader" ne semble pas être une notion très bien définie...

20voto

eznme Points 13158

J'ai dû regarder dans les spécifications :

La documentation de la classe getResource() indique la différence :

Cette méthode délègue l'appel à son chargeur de classe, après avoir apporté ces modifications au nom de la ressource : si le nom de la ressource commence par "/", il reste inchangé ; sinon, le nom du paquet est ajouté au nom de la ressource après avoir converti "." en "/". Si cet objet a été chargé par le chargeur d'amorçage, l'appel est délégué à ClassLoader.getSystemResource.

2 votes

Savez-vous s'il met également en cache la liste du répertoire ? C'était la principale différence entre les deux méthodes lors de la recherche d'un fichier d'entrée, puis de la création d'un fichier à partir de celui-ci dans le même répertoire. La version Class ne l'a pas trouvé, la version ClassLoader l'a trouvé (les deux utilisant "/file.txt").

11voto

Tim Büthe Points 21527

Toutes ces réponses par ici, ainsi que les réponses en cette question suggèrent que le chargement d'URL absolus, comme "/foo/bar.properties", est traité de la même manière par la Commission européenne. class.getResourceAsStream(String) y class.getClassLoader().getResourceAsStream(String) . Ce n'est PAS le cas, du moins pas dans ma configuration/version de Tomcat (actuellement 7.0.40).

MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!  
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!

Désolé, je n'ai absolument aucune explication satisfaisante, mais je suppose que tomcat fait de sales tours et sa magie noire avec les classloaders et cause la différence. J'ai toujours utilisé class.getResourceAsStream(String) dans le passé et n'ont pas eu de problèmes.

PS : J'ai aussi posté ceci sur aquí

0 votes

Ce comportement semble être un bogue dans Tomcat qui a été corrigé dans la version 8. J'ai ajouté un paragraphe à ce sujet dans mon réponse à cette question

7voto

mstoeckli Points 165

Pour répondre à la question de savoir si une mise en cache est en cours.

J'ai approfondi ce point en exécutant une application Java autonome qui chargeait continuellement un fichier à partir du disque en utilisant la méthode getResourceAsStream ClassLoader. J'ai pu modifier le fichier, et les modifications ont été reflétées immédiatement, c'est-à-dire que le fichier a été rechargé à partir du disque sans mise en cache.

Cependant : Je travaille sur un projet comportant plusieurs modules maven et projets web qui ont des dépendances les uns des autres. J'utilise IntelliJ comme IDE pour compiler et exécuter les projets Web.

J'ai remarqué que ce qui précède ne semblait plus être vrai, la raison étant que le fichier que j'étais en train de charger est maintenant intégré dans un jar et déployé dans le projet web dépendant. Je ne l'ai remarqué qu'après avoir essayé de modifier le fichier dans mon dossier cible, en vain. Cela m'a donné l'impression qu'une mise en cache était en cours.

0 votes

J'ai moi aussi utilisé Maven et IntelliJ, c'est donc la réponse dans un environnement qui se rapproche le plus du mien et qui donne une explication raisonnable à la question n°2.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X