Comprendre le fonctionnement du ClassLoader

Une fois n'est pas coutume, cet article a surtout une vocation d'aide-mémoire, mais j'espère qu'il permettra à certains de comprendre ces détails de la JVM.

Lors de l'utilisation d'un JAR exécutable, il est important de connaître l'influence de la tactique de lancement de l'application sur son comportement.

En effet, il existe deux lignes de commande pour exécuter un JAR :

java -jar thefile.jar

ou

java -cp ../conf/;package2;thefile.jar com.my.MainClass

Voici un exemple de leur influence.

Prenons une application structurée ainsi :

rootFolder/
|- conf/
  |- test.properties
|- script/
  |- thefile.jar! 
    |- test.properties

Le JAR contient, à sa racine, le fichier test.properties ainsi qu'un MANIFEST ajoutant au classpath le répertoire "../conf/". Le fichier test.properties situé dans ce dernier diffère de quelques ligne par rapport à celui du JAR.

Le code utilisé pour charger les propriétés est le suivant :

InputStream propStream = getClass().getClassLoader().getResourceAsStream("test.properties");

En lançant l'application avec la première ligne de commande, les propriétés chargées sont celles situées dans le JAR. En revanche, avec la seconde ligne de commande, ce sont celles situées dans le répertoire "conf"...

Pourquoi donc? Il faut se référer à la documentation du ClassLoader pour comprendre l'ordre de chargement des ressources (extrait) :

How the Java Launcher Finds User Classes
(...)
The user class path is specified as a string, with a colon (:) separating the class path entries on Solaris, and a semi-colon (;) separating entries on Microsoft Windows systems. The java launcher puts the user class path string in the java.class.path system property. The possible sources of this value are:
  • The default value, ".", meaning that user class files are all the class files in the current directory (or under it, if in a package).
  • The value of the CLASSPATH environment variable, which overrides the default value.
  • The value of the -cp or -classpath command line option, which overrides both the default value and the CLASSPATH value.
  • The JAR archive specified by the -jar option, which overrides all other values. If this option is used, all user classes must come from the specified archive.

Voici donc ce que l'on apprend :

  • la commande "-cp" surcharge l'utilisation de tout autre définition de classpath
  • la commande "-jar" surcharge tout autre commande de lancement. Ce n'est également que dans ce contexte qu'est utilisé le MANIFEST

Voilà donc pourquoi la seconde ligne de commande ne prend en compte que les propriétés situées dans le répertoire "conf". Information supplémentaire (lue entre les lignes) : dans le cas de l'utilisation d'un JAR avec la première ligne de commande, le ClassLoader suppose que toutes les ressources utiles sont situées dans le JAR... Ce n'est qu'après l'avoir entièrement chargé qu'il utilisera le MANIFEST pour récupérer les ressources manquantes. C'est la raison pour laquelle, dans ce scénario, seules les propriétés situées dans le jar sont utilisées!

Hope this helps...

Sources :


Fichier(s) joint(s) :

0 commentaires: