Aucun résultat trouvé

Votre recherche n’a donné aucun résultat.

Nous vous suggérons d’essayer ce qui suit pour trouver ce que vous recherchez :

  • Vérifiez l’orthographe de votre recherche par mot clé.
  • Utilisez des synonymes pour le mot clé que vous avez tapé, par exemple, essayez “application” au lieu de “logiciel”.
  • Essayez l’une des recherches populaires ci-dessous.
  • Lancer une nouvelle recherche.
Questions tendances

 

Java 9 | Extrait

Comprendre les modules de Java 9

À quoi servent-ils et comment les utiliser ?

Paul Deitel


Paul Deitel

Paul Deitel

Dans cet article, je vais vous présenter Java 9 Platform Module System (JPMS), la nouvelle technologie d'ingénierie logicielle la plus importante de Java depuis sa création. La modularité, qui résulte du projet Jigsaw, aide les développeurs à être plus productifs à tous les niveaux lorsqu'ils créent, maintiennent et font évoluer des systèmes logiciels, en particulier de grands systèmes.

Qu'est-ce qu'un module ?

La modularité ajoute un niveau d'agrégation plus élevé au-dessus des packages. Le nouvel élément de langage clé est le module, un groupe de packages connexes réutilisables et portant un nom unique, ainsi que des ressources (telles que des images et des fichiers XML) et un descripteur de module ( module descriptor) indiquant

  • le nom du module
  • les dépendances du module, c'est-à-dire les autres modules dont dépend ce module
  • les packages qu'il met explicitement à la disposition d'autres modules (tous les autres packages du module sont implicitement indisponibles pour d'autres modules)
  • les services qu'il offre
  • les services qu'il consomme
  • les autres modules à qui il autorise la réflexion

Historique

La plateforme Java SE existe depuis 1995. Aujourd'hui, environ 10 millions de développeurs l'utilisent pour des projets de toutes formes, des applications légères pour les appareils à ressources limitées, notamment pour l'Internet des objets (IoT) et d'autres appareils embarqués, aux systèmes stratégiques à grande échelle. Il existe d'importantes quantités de code hérité en production, mais jusqu'à présent, la plateforme Java était une solution monolithique universelle. Au fil des ans, divers projets ont été entrepris pour modulariser Java. Toutefois, aucun n'a largement été adopté et n'a donc pu participer à modulariser la plateforme Java.

La modularisation de la plateforme Java SE a été difficile à implémenter et ce projet a pris de nombreuses années. JSR 277 : Java Module System a été initialement proposé en 2005 pour Java 7. Ce JSR a ensuite été remplacé par JSR 376 : Java Platform Module System et ciblé pour Java 8. La plateforme Java SE est désormais modularisée depuis Java 9, mais il aura fallu retarder la sortie de Java 9 à septembre 2017.

Objectifs

Chaque module doit indiquer explicitement ses dépendances.

Selon JSR 376, les principaux objectifs de la modularisation de la plateforme Java SE sont

  • Une configuration fiable : la modularité fournit des mécanismes permettant de déclarer explicitement les dépendances entre les modules d'une manière reconnue à la fois lors de la compilation et lors de l'exécution. Le système peut parcourir ces dépendances pour déterminer le sous-ensemble de tous les modules requis pour prendre en charge votre application.
  • Une encapsulation forte : les packages d'un module ne sont accessibles aux autres modules que si le module les exporte explicitement. Même dans ce cas, un autre module ne peut pas utiliser ces packages à moins qu'il n'indique explicitement qu'il nécessite les capacités de l'autre module. Cette approche renforce la sécurité de la plateforme, car les pirates ont accès à moins de classes. Vous constaterez peut-être que la modularité vous aide à concevoir des programmes plus propres et plus logiques.
  • L'évolutivité de la plateforme Java : auparavant, la plateforme Java était un monolithique composé d'un grand nombre de packages. Le développement, la maintenance et l'évolution se révélaient donc difficiles. Il n'a pas été aisé d'établir des sous-divisions. La plateforme compte désormais 95 modules, un nombre qui pourra évoluer au gré des changements apportés à Java. Vous pouvez créer des environnements d'exécution personnalisés avec uniquement les modules dont vous avez besoin pour vos applications ou les appareils que vous ciblez. Par exemple, si un périphérique ne prend pas en charge les interfaces graphiques, vous pouvez créer un environnement d'exécution qui n'inclut pas les modules GUI, ce qui réduit considérablement la taille de l'environnement d'exécution.
  • Une intégrité accrue de la plateforme : avant Java 9, il était possible d'utiliser de nombreuses classes dans la plateforme qui n'étaient pas destinées à être utilisées par les classes d'une application. Avec une encapsulation forte, ces API internes sont vraiment encapsulées et cachées des applications utilisant la plateforme. Cela peut rendre la migration du code hérité vers Java 9 modularisé problématique si votre code dépend d'API internes.
  • Des performances accrues : la JVM utilise différentes techniques d'optimisation pour améliorer les performances des applications. JSR 376 indique que ces techniques sont plus efficaces lorsqu'on sait à l'avance que les types requis ne sont situés que dans des modules spécifiques.

Liste des modules de JDK

Un aspect crucial de Java 9 consiste à diviser le JDK en modules pour prendre en charge diverses configurations. (Consulter « JEP 200 : Le JDK modulaire. » Tous les JEP et JSR de modularité Java sont présentés dans le Tableau 1.) Utilisation de la commande java à partir du dossier bin du JDK avec l'option --list-modules, comme par exemple : 

java --list-modules

répertorie l'ensemble de modules du JDK, qui inclut les modules standard qui implémentent la spécification Java Language SE (noms commençant par java), les modules JavaFX (noms commençant par javafx), les modules propres au JDK (noms commençant par jdk) et les modules propres à Oracle (noms commençant par oracle). Chaque nom de module est suivi d'une chaîne de version : @9 indique que le module appartient à Java 9.

Déclarations de module

Comme nous l'avons mentionné, un module doit fournir un descripteur de module. Il s'agit de métadonnées qui spécifient les dépendances du module, les packages que le module met à la disposition d'autres modules, et plus encore. Un descripteur de module est la version compilée d'une déclaration de module définie dans un fichier nommé module-info.java. Chaque déclaration de module commence par le mot-clé module et est suivie d'un nom de module unique ainsi que d'un corps de module entre accolades, comme dans :

Une motivation clé du système de modules est une forte encapsulation.

module nom_du_module
}

Le corps de la déclaration de module peut être vide ou contenir diverses directives de module, notamment requires, exports, provides…with, uses et opens (nous aborderons chacune d'entre elles ci-après). Comme vous le verrez plus loin, la compilation de la déclaration de module crée le descripteur de module, qui est stocké dans un fichier nommé module-info.class dans le dossier racine du module. Nous présentons ici brièvement chaque directive de module. Après cela, nous présenterons les déclarations de module concrètes.

Les mots-clés exports, module, open, opens, provides, requires, uses, with, ainsi que to et transitive, que nous présenterons ultérieurement, sont des mots-clés restreints. Ce sont des mots-clés uniquement dans les déclarations de module et peuvent être utilisés comme identifiants partout ailleurs dans votre code.

requires. Une directive de module requires indique que ce module dépend d'un autre module. Cette relation est appelée dépendance de module. Chaque module doit indiquer explicitement ses dépendances. Lorsque le module A requiert (requires) le module B, le module A lit le module B et le module B est lu par le module A. Pour spécifier une dépendance sur un autre module, utilisez requires, comme dans :

requires nom_de_module;

Il existe également une directive requires static pour indiquer qu'un module est requis lors de la compilation, mais qu'il est facultatif lors de l'exécution. Il s'agit d'une dépendance optionnelle, un sujet qui ne sera pas abordé dans cette introduction.

requires transitive : lisibilité implicite. Pour spécifier une dépendance sur un autre module et pour vous assurer que les autres modules lisant votre module lisent également cette dépendance, appelée implied readability, utilisez requires transitive, comme dans :

requires transitive nom_de_module;

Examinez la directive suivante de la déclaration du module java.desktop :

requires transitive java.xml

Dans ce cas, tout module qui lit java.desktop lit également implicitement java.xml. Par exemple, si une méthode du module java.desktop renvoie un type du module java.xml, le code des modules qui lisent java.desktop dépend de java.xml. Sans la directive requires transitive dans la déclaration de module de java.desktop, ces modules dépendants ne sont compilés que s'ils lisent explicitly java.xml.

Selon JSR 379, les modules standard de Java SE doivent accorder une lisibilité implicite dans tous les cas comme celui décrit ici. En outre, si un module standard Java SE peut dépendre de modules non standard, il ne doit pas leur accorder une lisibilité implicite. Cela garantit que le code dépendant uniquement des modules standard Java SE est portable dans les implémentations Java SE.

exports et exports…to. Une directive de module exports indique qu'un des packages du module dont les types public (et leurs types public et protected imbriqués) doit être accessibles pour le code dans tous les autres modules. Une directive exports…to vous permet de spécifier, dans une liste séparée par des virgules, précisément le code du module ou des modules pouvant accéder au package exporté (export qualifié). 

uses. Une directive de module uses spécifie un service utilisé par ce module, ce qui en fait un consommateur de service. Un service est un objet d'une classe qui implémente l'interface ou étend la classe abstraite (abstract) spécifiée dans la directive uses.

provides…with. Une directive de module provides…with spécifie qu'un module fournit une implémentation de service, ce qui fait du module un fournisseur de services. La partie provides de la directive spécifie une interface ou une classe abstraite (abstract) répertoriée dans la directive uses d'un module et la partie with de la directive spécifie le nom de la classe du fournisseur de services qui implémente (implements) l'interface ou étend (extends) la classe abstraite (abstract).

open, opens, et opens…to. Avant Java 9, la réflexion pouvait être utilisée pour en savoir plus sur tous les types d'un package et sur tous les membres d'un type (même ses membres privés [private]), que vous souhaitiez autoriser ou non cette fonctionnalité. Rien n'était vraiment encapsulé.

Une forte encapsulation a été l'une des principales motivations pour le système de modules. Par défaut, un type dans un module n'est pas accessible aux autres modules, sauf s'il s'agit d'un type public et que vous exportez son package. Vous n'exposez que les packages que vous souhaitez exposer. Avec Java 9, cela s'applique également à la réflexion.

Autoriser l'accès à un package uniquement au moment de l'exécution. Une directive de module « opens » du type

opens package

indique que les types publics (public) d'un package spécifique (ainsi que leurs types publics [public] et protégés [protected] imbriqués) sont accessibles pour le code dans d'autres modules lors de l'exécution uniquement. En outre, tous les types du package spécifié (et tous les membres des types) sont accessibles par réflexion.

Autoriser l'accès à un package à exécution uniquement par des modules spécifiques. Une directive de module opens…to

opens package to liste-de-modules-séparés-par-des-virgules

indique que les types publics (public) d'un package spécifique (ainsi que leurs types publics [public] et protégés [protected] imbriqués) sont accessibles pour le code dans les modules listés lors de l'exécution uniquement. Tous les types du package spécifié (et tous les membres des types) sont accessibles par réflexion pour coder dans les modules spécifiés.

Autoriser l'accès à l'exécution uniquement à tous les packages d'un module. Si tous les packages d'un module donné doivent être accessibles lors de l'exécution et via la réflexion vers tous les autres modules, vous pouvez ouvrir (open) l'ensemble du module, comme dans :

open module nom_de_module {
   // directives de module

Valeurs par défaut de la réflexion

Par défaut, un module utilisant la réflexion à l'exécution pour un package peut voir les types publics (public) du package (et leurs types publics [public] et protégés [protected] imbriqués). Cependant, le code d'autres modules peut accéder à tous les types du package exposé et à tous les membres de ces types, y compris les membres privés (private) via setAccessible, comme dans les versions Java antérieures.

Pour plus d'informations sur setAccessible et la réflexion, reportez-vous à la documentation d'Oracle.


Paul Deitel, PDG et Directeur technique de Deitel & Associates, est diplômé du MIT. Il a 35 ans d'expérience en informatique. Il est un chantre de Java et programme avec ce langage depuis plus de 22 ans. Avec son co-auteur, le Dr Harvey M. Deitel, ils ont écrit plusieurs livres sur des langages de programmation qui ont connu un succès de librairie. Paul a dispensé des cours de programmation Java, Android, iOS, C#, C++, C et Internet à des clients industriels, gouvernementaux et universitaires à l'international.


REMARQUE : Cet article est extrait du Java Magazine de septembre/octobre 2017.

En savoir plus