Question

J'ai un chargeur de classes personnalisé qui permet à une application de bureau de démarrer de manière dynamique le chargement de classes à partir d'un serveur d'application auquel je dois parler. Nous l’avons fait car la quantité de bocaux nécessaires est ridicule (si nous voulions les expédier). Nous avons également des problèmes de version si nous ne chargeons pas les classes de manière dynamique au moment de l’exécution à partir de la bibliothèque AppServer.

Maintenant, je viens de rencontrer un problème qui me demandait de parler à deux serveurs d’appserveur différents et de constater que, selon les classes que je chargeais en premier, je risquais de me briser mal. Existe-t-il un moyen de forcer le déchargement de la classe sans tuer réellement la JVM?

J'espère que cela a du sens

Était-ce utile?

La solution

Le déchargement d'une classe est uniquement possible si le chargeur de classe utilisé est récupéré. Cela signifie que les références à chaque classe et au chargeur de classe lui-même doivent suivre le même chemin que le dodo.

Une solution possible à votre problème consiste à avoir un chargeur de classe pour chaque fichier JAR et un chargeur de classe pour chacun des serveurs AppServers qui délègue le chargement réel des classes à des chargeurs de classe Jar spécifiques. De cette façon, vous pouvez pointer vers différentes versions du fichier jar pour chaque serveur d'applications.

Ceci n’est cependant pas trivial. C'est ce que la plate-forme OSGi s'efforce de faire, chaque bundle ayant un chargeur de classe différent et les dépendances résolues par la plate-forme. Une bonne solution serait peut-être d'y jeter un coup d'œil.

Si vous ne souhaitez pas utiliser OSGI, une implémentation possible pourrait consister à utiliser une instance de JarClassloader pour chaque fichier JAR.

Et créez une nouvelle classe MultiClassloader qui étend Classloader. Cette classe aurait en interne un tableau (ou une liste) de JarClassloaders et, dans la méthode defineClass (), itérerait dans tous les chargeurs de classe internes jusqu'à ce qu'une définition soit trouvée ou qu'un exception NoClassDefFoundException soit levée. Deux méthodes d'accès peuvent être fournies pour ajouter de nouveaux JarClassloaders à la classe. Il existe plusieurs implémentations possibles sur le réseau pour un MultiClassLoader, vous n’avez donc peut-être même pas besoin d’écrire votre propre.

Si vous installez un MultiClassloader pour chaque connexion au serveur, il est en principe possible que chaque serveur utilise une version différente de la même classe.

J'ai utilisé l'idée de MultiClassloader dans un projet, où les classes contenant des scripts définis par l'utilisateur devaient être chargées et déchargées de la mémoire et cela fonctionnait plutôt bien.

Autres conseils

Oui, il existe des moyens de charger des classes et de "décharger". plus tard. L'astuce consiste à implémenter votre propre chargeur de classe qui réside entre le chargeur de classe de haut niveau (le chargeur de classe System) et les chargeurs de classe du ou des serveurs d'applications, et à espérer que les chargeurs de classe du serveur d'application délèguent le chargement de classe aux chargeurs supérieurs. .

Une classe est définie par son paquet, son nom et le chargeur de classe qu’elle a chargé à l’origine. Programmer un " proxy " classloader qui est le premier chargé lors du démarrage de la machine virtuelle Java. Flux de travail:

  • Le programme démarre et la classe "principale" est chargée par ce chargeur de classe proxy.
  • Chaque classe qui est alors normalement chargée (c'est-à-dire sans passer par une autre implémentation de chargeur de classe susceptible de rompre la hiérarchie) sera déléguée à ce chargeur de classe.
  • Les délégués de chargeur de classe proxy java.x et sun.x au chargeur de classes système (ceux-ci ne doivent pas être chargés via un autre chargeur de classes que le chargeur de classe du système).
  • Pour chaque classe remplaçable, instanciez un chargeur de classe (qui charge réellement la classe et ne le délègue pas au chargeur de classe parent) et chargez-le par ce biais.
  • Stockez le paquet / nom des classes en tant que clés et le chargeur de classes en tant que valeurs dans une structure de données (par exemple, Hashmap).
  • Chaque fois que le chargeur de classes proxy reçoit une demande pour une classe chargée auparavant, il renvoie la classe à partir du chargeur de classes stocké auparavant.
  • Il devrait suffire de localiser le tableau d'octets d'une classe à l'aide de votre chargeur de classes (ou de "supprimer" la paire clé / valeur de votre structure de données) et de recharger la classe au cas où vous souhaiteriez la modifier.

Bien fait, il ne devrait pas y avoir de ClassCastException ou LinkageError , etc.

Pour plus d'informations sur les hiérarchies de chargeur de classes (oui, c'est exactement ce que vous implémentez ici; -), consultez la section " ; Programmation Java sur serveur " par Ted Neward - ce livre m'a aidé à mettre en œuvre quelque chose de très similaire à ce que vous voulez.

J'ai écrit un chargeur de classes personnalisé, à partir duquel il est possible de décharger des classes individuelles sans configurer le chargeur de classes. Chargeur de classes Jar

Les chargeurs de classes peuvent être un problème épineux. Vous pouvez notamment rencontrer des problèmes si vous utilisez plusieurs chargeurs de classe et que leurs interactions ne sont pas définies clairement et rigoureusement. Je pense que pour pouvoir décharger une classe, vous devez supprimer toutes les références aux classes (et à leurs instances) que vous essayez de décharger.

La plupart des personnes qui ont besoin de faire ce genre de choses finissent par utiliser OSGi . OSGi est vraiment puissant et étonnamment léger et facile à utiliser,

Vous pouvez décharger un ClassLoader mais vous ne pouvez pas décharger des classes spécifiques. Plus spécifiquement, vous ne pouvez pas décharger les classes créées dans un chargeur de classe qui n’est pas sous votre contrôle.

Si possible, je suggère d'utiliser votre propre ClassLoader afin de pouvoir le décharger.

Les classes ont une forte référence implicite à leur instance de ClassLoader, et inversement. Ils sont ramassés comme avec les objets Java. Sans toucher à l’interface d’outils ou similaire, vous ne pouvez pas supprimer des classes individuelles.

Comme toujours, vous pouvez avoir des fuites de mémoire. Toute référence forte à l'une de vos classes ou à un chargeur de classe perdra toute trace. Cela se produit avec les implémentations Sun de ThreadLocal, java.sql.DriverManager et java.beans, par exemple.

Si vous regardez en direct si la classe de déchargement fonctionne dans JConsole ou quelque chose du genre, essayez également d’ajouter à java.lang.System.gc () à la fin de la logique de déchargement de votre classe. Il déclenche explicitement le ramasse-miettes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top