Chapitre 3. Chargement de classes modulaire et modules

3.1. Introduction

3.1.1. Chargement des classes de chargement et de modules

JBoss EAP 6 utilise un nouveau système de chargement de classes modulaire pour contrôler les chemins de classe d'applications déployées. Ce système offre plus de souplesse et de contrôle que le système traditionnel des chargeurs de classes hiérarchiques. Les développeurs ont un contrôle précis des classes disponibles à leurs applications et peuvent configurer un déploiement pour qu'il puisse ignorer les classes fournies par le serveur d'application en faveur de leurs propres classes.
Le nouveau chargeur de classes modulaire sépare toutes les classes Java en des groupes logiques appelés modules. Chaque module peut définir des dépendances sur d'autres modules de manière à ajouter les classes de ces modules dans leur propre chemin de classe. Le fait que chaque fichier JAR et WAR déployé soit traité comme un module permet aux développeurs de contrôler le contenu du chemin de classe de leur application en ajoutant une configuration de module à leur application.

3.1.2. Chargement des classes

Le chargement des classes est un mécanisme par lequel les classes et les ressources Java sont chargées dans l'environnement d'exécution de Java (Java Runtime Environment).

3.1.3. Modules

Un module est un regroupement logique des classes utilisées pour le chargement de classes et pour la gestion des dépendances. JBoss EAP 6 identifie deux types de modules, parfois appelés modules statiques et dynamiques. Cependant, la seule différence entre les deux est la façon dont ils sont empaquetés. Tous les modules offrent les mêmes caractéristiques.
Modules statiques
Les modules statiques sont prédéfinis dans le répertoire EAP_HOME/modules/ du serveur d'applications. Chaque sous-répertoire représente un module et contient un fichier de configuration (module.xml) et tout fichier JAR requis. Le nom du module est défini dans le fichier module.xml. Tous les API fournis par le serveur de l'application sont des modules statiques, y compris les API Java EE, et les autres API comme JBoss Logging.

Exemple 3.1. Exemple de fichier module.xml

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="com.mysql">
  <resources>
    <resource-root path="mysql-connector-java-5.1.15.jar"/>
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>
Le nom du module, com.mysql, doit correspondre à la structure du répertoire du module.
Les modules fournis dans les distributions JBoss EAP se trouvent dans un répertoire system se trouvant lui-même dans le répertoire JBOSS_HOME/modules. Cela les rend séparés de tout module fourni par une tierce partie.
Tout produit mis en couche de Red Hat, se superposant sur JBoss EAP 6.1 ou version supérieure installera également leurs modules dans le répertoire system.
La création de modules statiques personnalisés peut être utile si plusieurs applications sont déployées sur un même serveur utilisant les mêmes bibliothèques de tierce partie. Au lieu d'un regroupement de ces bibliothèques pour chaque application, un module contenant ces bibliothèques peut être créé et installé par l'administrateur JBoss. Les applications peuvent ensuite déclarer une dépendance explicite sur les modules statiques personnalisés.
Les utilisateurs doivent s'assurer que les modules personnalisés soient installés dans le répertoire JBOSS_HOME/modules, en utilisant un répertoire par couche de modules. Cela garantit que les versions personnalisées de modules qui existent déjà dans le répertoire system soient bien chargées à la place des versions fournies. Ainsi, les modules utilisateur auront la priorité sur les modules fournis par le système.
Si vous utilisez la variable d'environnement JBOSS_MODULE_PATH pour changer les emplacements où JBoss EAP cherche les modules, le produit ira chercher dans une structure de sous-répertoire system dans un des emplacements spécifiés. Une structure de sous-répertoire system doit exister quelquepart dans les emplacements spécifiés dans JBOSS_MODULE_PATH.
Modules dynamiques
Les modules dynamiques sont créés et chargés par le serveur d'application pour chaque déploiement JAR ou WAR (ou sous-déploiement d'un EAR). Le nom d'un module dynamique est dérivé du nom de l'archive déployée. Comme les déploiements sont chargés sous forme de modules, ils peuvent configurer des dépendances et peuvent être utilisés comme dépendances par d'autres déploiements.
Les modules ne sont chargés qu'en fonction des besoins. Cela a généralement lieu quand une application est déployée avec des dépendances implicites ou explicites.

3.1.4. Les dépendances de modules

Une dépendance de module est une déclaration qui indique qu'un module a besoin des classes d'un autre module pour pouvoir fonctionner. Les modules peuvent déclarer leurs dépendances sur un certain nombre d'autres modules. Quand le serveur d'applications charge un module, le chargeur de classes de module traite les dépendances de ce module et ajoute les classes de chaque dépendance à son chemin de classe. Si une dépendance particulière est introuvable, le module ne pourra pas charger.
Les applications déployées (JAR et WAR) sont chargées sous forme de modules dynamiques et utilisent des dépendances pour accéder aux API fournies par JBoss EAP 6.
Il y a deux types de dépendances : explicite et implicite.
Les dépendances explicites sont déclarées dans la configuration par le développeur. Les modules statiques peuvent déclarer des dépendances dans le fichier modules.xml. Les modules dynamiques peuvent avoir des dépendances déclarées dans les descripteurs de déploiement MANIFEST.MF ou jboss-deployment-structure.xml.
Les dépendances explicites peuvent être spécifiées comme étant optionnelles. Une erreur de chargement de dépendance optionnelle n'entraînera pas l'annulation d'un chargement de module. Cependant, si la dépendance est rendue disponible par la suite, elle ne sera PAS ajoutée au chemin de classe du module. Les dépendances doivent être rendues disponibles quand le module est chargé.
Des dépendances implicites sont ajoutées automatiquement par le serveur d'applications quand certaines conditions ou meta-données se trouvent dans un déploiement. Les API Java EE 6 fournies avec JBoss EAP 6 sont des exemples de modules ajoutés par détection de dépendances implicites dans les déploiements.
Les déploiements peuvent également être configurés de façon à exclure des dépendances implicites particulières. Il vous faut pour cela le fichier de déploiement jboss-deployment-structure.xml. C'est normalement le cas quand une application empaquète une version spécifique de bibliothèque que le serveur d'applications tentera d'ajouter comme dépendance implicite.
Un chemin de classe de module ne contient que ses propres classes et celles de ses dépendances immédiates. Un module n'est pas en mesure d'accéder aux classes des dépendances. Cependant, un module peut indiquer quand une dépendance explicite est exportée. Une dépendance exportée est fournie à tout module qui dépend du module qui l'exporte.

Exemple 3.2. Les dépendances de module

Le Module A dépend du Module B et le Module B dépend su Module C. Le Module A peut accéder aux classes du Module B, et le Module B peut accéder aux classes du Module C. Le Module C ne peut pas accéder aux classes du Module C à moins que :
  • Le Module A déclare une dépendance explicite sur le Module C, ou bien
  • Le Module B exporte ses dépendances sur le Module C.

3.1.5. Chargement des classes dans les déploiements

Dans le cadre du chargement de classes, tous les déploiements sont traités sous forme de modules par JBoss EAP 6. On les appelle des modules dynamiques. Les comportements de chargement de classes varient selon le type de déploiement.
Déploiement WAR
Un déploiement WAR est un simple module. Les classes du répertoire WEB-INF/lib sont considérées de la même manière que celles du répertoire WEB-INF/classes. Toutes les classes empaquetées dans le war seront téléchargées par le même chargeur de classes.
Déploiement EAR
Les déploiements EAR sont faits de plus d'un module. La définition de ces modules suit ces règles :
  1. Le répertoire lib/ du EAR est un simple module nommé le module parent.
  2. Chaque déploiement WAR du EAR est un simple module.
  3. Chaque déploiement EJB JAR du EAR est un simple module.
Les modules de sous-déploiement (les déploiements WAR et JAR dans EAR) ont une dépendance automatique sur le module parent. Cependant ils n'ont pas de dépendance automatique l'un sur l'autre. Ceci est appelé l'isolement du sous-déploiement et peut être désactivé par déploiement ou pour le serveur de toute l'application dans son ensemble.
Les dépendances explicites entre les modules de sous-déploiement peuvent être ajoutées par les mêmes moyens, tout comme pour tout autre module.

3.1.6. Précédence pour le chargement des classes

Le chargeur de classes modulaires JBoss EAP 6 utilise un système de priorité pour empêcher le chargement des conflits de classes.
Pendant le déploiement, la liste complète des packages et des classes est créée pour chaque déploiement et chacune de ses dépendances. La liste est ordonnée selon les règles de priorité de chargement de classes. Lors du chargement de classes au moment de l'exécution, le chargeur de classes recherche dans cette liste et charge la première correspondance. Cela empêche plusieurs copies des mêmes classes et packages dans le chemin d'accès de classe des déploiements d'entrer en conflit l'un avec l'autre.
Le chargeur de classe charge les classes dans l'ordre suivant, du plus élevé au plus bas :
  1. Dépendances implicites.
    Voici les dépendances qui sont ajoutées automatiquement par JBoss EAP 6, comme les API JAVA EE. Ces dépendances ont la plus haute précédence de chargeur de classe car ils contiennent des API et des fonctionnalités communes qui sont fournies par JBoss EAP 6.
    Voir Section 3.8.1, « Dépendances de modules implicites » pour obtenir des détails sur chaque dépendance implicite.
  2. Dépendances explicites
    Il s'agit de dépendances qui sont ajoutées manuellement dans la configuration de l'application. Cela peut être fait à l'aide du fichier d'application MANIFEST.MF ou du nouveau fichier du descripteur de déploiement en option de JBoss jboss-deployment-structure.xml.
    Voir Section 3.2, « Ajouter une dépendance de module explicite à un déploiement » pour apprendre comment ajouter des dépendances explicites.
  3. Ressources locales.
    Fichiers de classe empaquetées à l'intérieur du déploiement lui-même, par ex. les répertoires WEB-INF/classes ou WEB-INF/lib d'un fichier WAR.
  4. Dépendances inter-déploiement.
    Ce sont des dépendances sur les autres déploiements d'un déploiement EAR. Cela peut inclure des classes du répertoire lib du EAR ou des classes des autres jars EJB.

3.1.7. Nommage de modules dynamiques

Tous les déploiements sont chargés en tant que modules par JBoss EAP 6 et sont nommés en fonction des conventions suivantes :
  1. Les déploiements des fichiers WAR et JAR sont nommés selon le format suivant :
     deployment.DEPLOYMENT_NAME 
    Par exemple, inventory.war et store.jar auront les mêmes noms de module que deployment.inventory.war et deployment.store.jar respectivement.
  2. Les sous-déploiements des archives Enterprise sont nommés selon le format suivant :
     deployment.EAR_NAME.SUBDEPLOYMENT_NAME 
    Ainsi, le sous-déploiement reports.war, qui se trouve dans l'archive Enterprise accounts.ear, aura le nom de module du deployment.accounts.ear.reports.war.

3.1.8. jboss-deployment-structure.xml

jboss-deployment-structure.xml est un descripteur de déploiement optionnel de JBoss EAP 6. Ce descripteur de déploiement fournit un contrôle pour le chargement de classes dans le déploiement.
Le schéma XML de ce descripteur de déploiement se trouve dans EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd