J'ai un chargeur de classe personnalisé pour qu'une application de bureau puisse démarrer dynamiquement le chargement de classes à partir d'un serveur AppServer avec lequel je dois parler. Nous l'avons fait car la quantité de bocaux nécessaires pour ce faire est ridicule (si nous voulions les expédier). Nous avons également des problèmes de version si nous ne chargeons pas les classes dynamiquement au moment de l'exécution à partir de la bibliothèque AppServer.
Maintenant, je viens de rencontrer un problème où j'ai besoin de parler à deux AppServers différents et j'ai trouvé que selon les classes que je charge en premier, je pourrais mal casser ... Y a-t-il un moyen de forcer le déchargement de la classe sans réellement tuer la JVM?
J'espère que cela a du sens
la source
Réponses:
La seule façon dont une classe peut être déchargée est si le chargeur de classe utilisé est garbage collection. Cela signifie que les références à chaque classe et au chargeur de classe lui-même doivent suivre la voie du dodo.
Une solution possible à votre problème consiste à avoir un Classloader pour chaque fichier jar et un Classloader pour chacun des AppServers qui délègue le chargement réel des classes à des classloaders Jar spécifiques. De cette façon, vous pouvez pointer vers différentes versions du fichier jar pour chaque serveur d'applications.
Ce n'est pas anodin, cependant. La plate-forme OSGi s'efforce de faire exactement cela, car chaque bundle a un chargeur de classe différent et les dépendances sont résolues par la plate-forme. Peut-être qu'une bonne solution serait de l'examiner.
Si vous ne souhaitez pas utiliser OSGI, une implémentation possible pourrait être d'utiliser une instance de la classe 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 à travers tous les chargeurs de classe internes jusqu'à ce qu'une définition puisse être trouvée, ou qu'une NoClassDefFoundException soit levée. Quelques méthodes d'accès peuvent être fournies pour ajouter de nouveaux JarClassloaders à la classe. Il existe plusieurs implémentations possibles sur le net pour un MultiClassLoader, vous n'aurez donc peut-être même pas besoin d'écrire la vôtre.
Si vous instanciez 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 très bien.
la source
Oui, il existe des moyens de charger des classes et de les "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 (des) serveur (s) d'application, et d'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 package, son nom et le chargeur de classe qu'elle a initialement chargé. Programmez un classloader "proxy" qui est le premier chargé au démarrage de la JVM. Flux de travail:
java.x
etsun.x
au chargeur de classe système (ceux-ci ne doivent pas être chargés via un autre chargeur de classe que le chargeur de classe système).Fait juste là ne devrait pas venir une ClassCastException ou LinkageError etc.
Pour plus d'informations sur les hiérarchies des chargeurs de classes (oui, c'est exactement ce que vous implémentez ici; -) regardez "Server-Based Java Programming" par Ted Neward - ce livre m'a aidé à implémenter quelque chose de très similaire à ce que vous voulez.
la source
ClassLoader
par classe est un peu trop, unClassLoader
par JAR a du sens. Pourrait être plus précis sur la façon de forcer le téléchargement de classe dans le schéma proposé? Par exemple, comment puis-je garantir que les instances de classes chargées par ClassLoaderA ne sont pas référencées par des instances chargées par ClassLoaderB?J'ai écrit un classloader personnalisé, à partir duquel il est possible de décharger des classes individuelles sans GCing le classloader. Chargeur de classe Jar
la source
JarClassLoader
pour chaque fichier jar que vous avez chargé, vous pouvez l'appelergetLoadedClasses()
, puis parcourir chacun d'eux et le décharger.Les chargeurs de classe peuvent être un problème délicat. Vous pouvez particulièrement rencontrer des problèmes si vous utilisez plusieurs chargeurs de classe et que leurs interactions ne sont pas clairement et rigoureusement définies. Je pense que pour pouvoir décharger une classe, vous devrez supprimer toutes les références à toutes les classes (et leurs instances) que vous essayez de décharger.
La plupart des gens qui ont besoin de faire ce type de chose finissent par utiliser OSGi . OSGi est vraiment puissant et étonnamment léger et facile à utiliser,
la source
Vous pouvez décharger un ClassLoader mais vous ne pouvez pas décharger des classes spécifiques. Plus précisément, vous ne pouvez pas décharger les classes créées dans un ClassLoader qui n'est pas sous votre contrôle.
Si possible, je suggère d'utiliser votre propre ClassLoader afin que vous puissiez décharger.
la source
Les classes ont une référence forte implicite à leur instance ClassLoader, et vice versa. Ils sont récupérés comme avec les objets Java. Sans accéder à l'interface des 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 chargeur de classe fera fuir le tout. Cela se produit avec les implémentations Sun de ThreadLocal, java.sql.DriverManager et java.beans, par exemple.
la source
Si vous regardez en direct si le déchargement de la classe a fonctionné dans JConsole ou quelque chose du genre , essayez également d'ajouter
java.lang.System.gc()
à la fin de votre logique de déchargement de classe. Il déclenche explicitement Garbage Collector.la source