Java, Classpath, Classloading => Plusieurs versions du même jar / projet

Je sais que cela peut être une question stupide pour les codeurs expérimentés. Mais j’ai une bibliothèque (un client http) que certains des autres frameworks / jars utilisés dans mon projet requièrent. Mais tous nécessitent des versions majeures différentes comme:

httpclient-v1.jar => Required by cralwer.jar httpclient-v2.jar => Required by restapi.jar httpclient-v3.jar => required by foobar.jar 

Le chargeur de classe est-il assez intelligent pour les séparer? Préférablement pas? Comment le Classloader gère-t-il cela, dans le cas où une classe est la même dans les trois jars. Lequel est chargé et pourquoi?

Le Classloader ne prend-il que exactement un pot ou mélange-t-il les classes de manière arbitraire? Donc, par exemple, si une classe est chargée à partir de la version 1.jar, toutes les autres classes chargées à partir du même chargeur de classes iront toutes dans le même jar?

Comment gérez-vous ce problème?

Y a-t-il une astuce pour “incorporer” les jars dans le fichier “required.jar” de manière à ce qu’ils soient considérés comme “une unité / paquet” par le Classloader , ou liés d’une manière ou d’une autre?

Les problèmes liés au chargeur de classe sont assez complexes. Vous devez en tout cas garder à l’esprit certains faits:

  • Les chargeurs de classe dans une application sont généralement plusieurs. La classe bootstrap charge le délégué approprié. Lorsque vous instanciez une nouvelle classe, le chargeur de classe plus spécifique est appelé. S’il ne trouve pas de référence à la classe que vous essayez de charger, il délègue à son parent, et ainsi de suite, jusqu’à ce que vous arriviez au chargeur de classe bootstrap. Si aucun d’entre eux ne trouve une référence à la classe que vous essayez de charger, vous obtenez une exception ClassNotFoundException.

  • Si vous avez deux classes avec le même nom binary, consultables par le même chargeur de classes et que vous voulez savoir lequel des deux vous chargez, vous ne pouvez inspecter que la manière dont un chargeur de classe spécifique tente de résoudre un nom de classe.

  • Selon la spécification du langage Java, il n’y a pas de contrainte d’unicité pour un nom de classe binary, mais pour autant que je sache, il devrait être unique pour chaque chargeur de classe.

Je peux trouver un moyen de charger deux classes avec le même nom binary, et cela implique de les charger (et toutes leurs dépendances) par deux chargeurs de classes différents remplaçant le comportement par défaut. Un exemple approximatif:

  ClassLoader loaderA = new MyClassLoader(libPathOne); ClassLoader loaderB = new MyClassLoader(libPathTwo); Object1 obj1 = loaderA.loadClass("first.class.binary.name", true) Object2 obj2 = loaderB.loadClass("second.class.binary.name", true); 

J’ai toujours trouvé la personnalisation de classloader une tâche délicate. Je préfère suggérer d’éviter autant de dépendances incompatibles si possible.

Chaque classe charge sélectionne exactement une classe. Généralement le premier trouvé.

OSGi vise à résoudre le problème des versions multiples du même pot. Equinox et Apache Felix sont les implémentations open-source communes à OSGi.

Classloader charge les classes à partir du fichier jar qui se trouvait en premier lieu dans le classpath. Normalement, les versions incompatibles de la bibliothèque ont des paquets différents, mais dans le cas peu probable, elles sont vraiment incompatibles et ne peuvent pas être remplacées par une seule – essayez jarjar.

Les chargeurs de classe chargent la classe à la demande. Cela signifie que la classe requirejse en premier par votre application et les bibliothèques associées serait chargée avant les autres classes; La demande de chargement des classes dépendantes est généralement émise pendant le processus de chargement et de liaison d’une classe dépendante.

Vous êtes susceptible de rencontrer LinkageError indiquant que des définitions de classes en double ont été rencontrées pour les chargeurs de classes en général ne tentent pas de déterminer quelle classe doit être chargée en premier (si plusieurs classes du même nom sont présentes dans le classpath du chargeur). Parfois, le chargeur de classe charge la première classe apparaissant dans le chemin de classe et ignore les classes en double, mais cela dépend de l’implémentation du chargeur.

La méthode recommandée pour résoudre ce type d’erreurs consiste à utiliser un chargeur de classe distinct pour chaque ensemble de bibliothèques ayant des dépendances en conflit. De cette façon, si un chargeur de classe tente de charger des classes à partir d’une bibliothèque, les classes dépendantes seraient chargées par le même chargeur de classes qui n’a pas access aux autres bibliothèques et dépendances.