web-dev-qa-db-fra.com

Chargement des classes et des ressources dans Java 9

Je lisais cet article sur InfoQ citant Reinhold:

Les développeurs peuvent toujours utiliser le chemin d'accès à la classe Java dans Java 9 pour le runtime Java) pour rechercher des classes et des fichiers de ressources. C'est juste qu'avec les modules de Java 9, les développeurs n'ont plus besoin du chemin de classe.

Alors maintenant, ma question est: quelle est la bonne Java 9 façon de faire les tâches énumérées ci-dessus? Comment charger dynamiquement, par exemple, une image (à moins de jouer avec les chemins relatifs)?

Plus intéressant encore, comment vérifier si une classe est disponible et prendre une décision de manière dynamique (par exemple, vérifier si Jackson est disponible et, si oui, l'utiliser pour la sérialisation JSON et sinon utiliser autre chose)?

L'article mentionne également que Spring Boot prend déjà en charge Java 9, et Spring Boot effectue certainement beaucoup de chargement dynamique. Alors peut-être que quelqu'un connaît le morceau de code de Spring que je peux regarder?

39
kaqqao

Premièrement, pour remettre les pendules à l'heure, je n'ai ni dit ni écrit le texte cité ci-dessus. Je ne l'aurais jamais dit ainsi. C’est juste un rapport bâclé de la part des publications concernées.

La chose la plus importante à comprendre au sujet du chargement de classe et de la recherche de ressources dans Java 9 est que, à un niveau fondamental, ils n'ont pas changé. Vous pouvez rechercher des classes et des ressources de la même manière que vous le faites toujours, en appelant Class::forName Et les différentes méthodes getResource* Dans les classes Class et ClassLoader , que votre code soit chargé à partir du chemin de classe ou du chemin de module. Il y a toujours trois chargeurs de classe intégrés, tout comme il y en avait dans JDK 1.2, et ils ont les mêmes relations de délégation. Beaucoup de code existant fonctionne donc juste, prêt à l'emploi.

Il y a quelques nuances, comme indiqué dans JEP 261 : Le type concret des chargeurs de classe intégrés a changé, et certaines classes anciennement chargées par le chargeur de classe bootstrap sont maintenant chargées par le chargeur de classe de plate-forme afin d'améliorer la sécurité. Le code existant qui suppose qu'un chargeur de classe intégré est un URLClassLoader, ou qu'une classe est chargée par le chargeur de classe bootstrap, peut donc nécessiter des ajustements mineurs.

Une dernière différence importante est que les ressources de fichiers non-classe dans un module sont encapsulées par défaut, et donc ne peuvent pas être localisées depuis l'extérieur du module à moins que leur package effectif ne soit open . Pour charger des ressources à partir de votre propre module, il est préférable d'utiliser les méthodes de recherche de ressources dans Class ou Module, qui peuvent localiser n'importe quelle ressource dans votre module, plutôt que celles dans ClassLoader , qui peut uniquement localiser des ressources de fichiers non-classe dans les packages open d'un module.

85
Mark Reinhold

[Modifier: cette réponse a été écrite avant la réponse faisant autorité de Mark. J'ai révisé le mien pour fournir un exemple simple, disponible sur GitHub .]

Par cette vidéo , le chargement de classe dans Java 9 est inchangé.

À titre d'exemple, disons que nous avons:

  • un example.jar qui contient une image dans le package net.codetojoy.example.resources
  • pour étoffer le pot, net.codetojoy.example.Composer est public (et exporté, le cas échéant)
  • une simple classe App qui utilise example.jar en tant que bibliothèque et tente de charger l'image à partir de celle-ci

Le code pertinent dans App:

static InputStream getResourceAsStream(String resource) 
    throws Exception {

    // Load net/codetojoy/example/resource/image.jpg
    // Assume net.codetojoy.example.Composer is public/exported
    // resource is 'resource/image.jpg'

    InputStream result = Composer.class.getResourceAsStream(resource);

    return result;
}   

Voici quelques cas pour example.jar dans JDK 9:

Pot non modulaire à l'ancienne

Si example.jar n'est pas un module, le code fonctionne juste. Le chargement des classes est inchangé.

Pot modulaire avec paquet ouvert

Dans ce cas, c'est le module-info.Java fichier:

module net.codetojoy.example {
    // export the Composer class
    exports net.codetojoy.example;

    // image is available
    opens net.codetojoy.example.resources;
}

Dans ce cas, l'image peut être chargée par le client, car le package est ouvert.

Pot modulaire sans paquet ouvert

Dans ce cas, module-info.Java est:

module net.codetojoy.example {
    // export the Composer class
    exports net.codetojoy.example;

    // package not opened: image not available
    // opens net.codetojoy.example.resources;
}

Dans ce cas, l'image ne peut pas être chargée, en raison d'une forte encapsulation: le module protège l'image en n'ouvrant pas le paquet.

Source complète ici sur GitHub .

4
Michael Easter