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 AppServer auquel je dois parler. Nous l'avons fait car la quantité de bocaux requis 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 oblige à parler à deux serveurs d'applications différents et à constater que, selon les classes que je charge en premier, je risquais de ne pas bien fonctionner ... 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
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 sur différentes versions du fichier jar pour chaque serveur d'applications.
Ce n'est pas trivial, cependant. C'est ce que la plate-forme OSGi s'efforce de faire, car chaque bundle a un chargeur de classe différent et que les dépendances sont résolues par la plate-forme. Peut-être une bonne solution serait-elle d'y jeter un coup d'œil.
Si vous ne souhaitez pas utiliser OSGI, une implémentation possible pourrait consister à utiliser une instance de la classe JarClassloader pour chaque fichier JAR.
Et créez une nouvelle classe MultiClassloader qui étend Classloader. En interne, cette classe aurait un tableau (ou une liste) de JarClassloaders et, dans la méthode defineClass (), itérerait dans tous les chargeurs de classes 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 y a plusieurs implémentations possibles sur le net pour un MultiClassLoader, vous n'avez 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 MultiClassloader dans un projet, dans lequel 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 assez bien.
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 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. Programmez un chargeur de classe "proxy" qui est le premier chargé lors du démarrage de la machine virtuelle Java. Flux de travail:
Java.x
et Sun.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 correctement, 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; -), regardez "Basé sur un serveur Java Programmation" de Ted Neward - que livre m'a aidé à mettre en œuvre quelque chose de très similaire à ce que vous voulez.
J'ai écrit un chargeur de classe personnalisé, à partir duquel il est possible de décharger des classes individuelles sans configurer le chargeur de classes. chargeur de classe Jar
Les chargeurs de classes peuvent être un problème délicat. 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 gens ayant besoin de faire ce genre de chose 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 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 Garbage Collector.