Tengo un cargador de clases personalizado para que una aplicación de escritorio pueda comenzar a cargar dinámicamente clases desde un AppServer con el que necesito hablar. Lo hicimos ya que la cantidad de frascos necesarios para hacer esto es ridícula (si quisiéramos enviarlos). También tenemos problemas de versión si no cargamos las clases dinámicamente en tiempo de ejecución desde la biblioteca AppServer.
Ahora, me topé con un problema en el que necesito hablar con dos AppServers diferentes y descubrí que, dependiendo de las clases que cargue primero, podría romper mal ... ¿Hay alguna forma de forzar la descarga de la clase sin matar realmente la JVM?
Espero que esto tenga sentido
java
classloader
el_eduardo
fuente
fuente
Respuestas:
La única forma en que una clase se puede descargar es si el cargador de clases utilizado es recolección de basura. Esto significa que las referencias a cada clase y al cargador de clases en sí deben seguir el camino del dodo.
Una posible solución a su problema es tener un cargador de clases para cada archivo jar y un cargador de clases para cada uno de los servidores de aplicaciones que delegue la carga real de clases a cargadores de clases Jar específicos. De esa manera, puede apuntar a diferentes versiones del archivo jar para cada servidor de aplicaciones.
Sin embargo, esto no es trivial. La plataforma OSGi se esfuerza por hacer exactamente esto, ya que cada paquete tiene un cargador de clases diferente y las dependencias son resueltas por la plataforma. Tal vez una buena solución sería echarle un vistazo.
Si no desea utilizar OSGI, una posible implementación podría ser utilizar una instancia de la clase JarClassloader para cada archivo JAR.
Y cree una nueva clase MultiClassloader que amplíe Classloader. Esta clase internamente tendría una matriz (o Lista) de JarClassloaders, y en el método defineClass () iteraría a través de todos los cargadores de clase internos hasta que se pueda encontrar una definición, o se arroje una NoClassDefFoundException. Se pueden proporcionar un par de métodos de acceso para agregar nuevos JarClassloaders a la clase. Hay varias implementaciones posibles en la red para un MultiClassLoader, por lo que es posible que ni siquiera necesite escribir el suyo.
Si instancia un MultiClassloader para cada conexión al servidor, en principio es posible que cada servidor use una versión diferente de la misma clase.
Utilicé la idea de MultiClassloader en un proyecto, donde las clases que contenían scripts definidos por el usuario tenían que cargarse y descargarse de la memoria y funcionaban bastante bien.
fuente
Sí, hay formas de cargar clases y "descargarlas" más adelante. El truco consiste en implementar su propio cargador de clases que reside entre el cargador de clases de alto nivel (el cargador de clases del sistema) y los cargadores de clases de los servidores de aplicaciones, y esperar que los cargadores de clases del servidor de aplicaciones deleguen la carga de clases en los cargadores superiores .
Una clase se define por su paquete, su nombre y el cargador de clases que cargó originalmente. Programe un cargador de clases "proxy", que es el primero que se carga al iniciar la JVM. Flujo de trabajo:
java.x
ysun.x
al cargador de clases del sistema (estos no deben cargarse a través de ningún otro cargador de clases que no sea el cargador de clases del sistema).Hecho justo allí no debería venir una ClassCastException o LinkageError, etc.
Para obtener más información sobre las jerarquías de cargadores de clases (sí, eso es exactamente lo que está implementando aquí; -) mire "Programación Java basada en servidor" de Ted Neward : ese libro me ayudó a implementar algo muy similar a lo que desea.
fuente
ClassLoader
por clase es demasiado, unoClassLoader
por JAR tiene sentido. ¿Podría ser más específico sobre cómo forzar la carga de clases en el esquema propuesto? Por ejemplo, ¿cómo puedo garantizar que las instancias de clases cargadas por ClassLoaderA no sean referidas por instancias cargadas por ClassLoaderB?Escribí un cargador de clases personalizado, desde el cual es posible descargar clases individuales sin GCing el cargador de clases. Jar Class Loader
fuente
JarClassLoader
para cada archivo jar que cargó, puedegetLoadedClasses()
invocarlo, luego iterar sobre cada uno y descargarlo.Los cargadores de clases pueden ser un problema complicado. Especialmente puede encontrarse con problemas si está utilizando múltiples cargadores de clases y no tiene sus interacciones definidas de manera clara y rigurosa. Creo que para poder realmente descargar una clase que vas a tener que eliminar todas las referencias a las clases (y sus instancias) que intentas descargar.
La mayoría de las personas que necesitan hacer este tipo de cosas terminan usando OSGi . OSGi es realmente potente y sorprendentemente ligero y fácil de usar,
fuente
Puede descargar un ClassLoader pero no puede descargar clases específicas. Más específicamente, no puede descargar clases creadas en un ClassLoader que no está bajo su control.
Si es posible, sugiero usar su propio ClassLoader para que pueda descargar.
fuente
Las clases tienen una fuerte referencia implícita a su instancia de ClassLoader, y viceversa. Son basura recolectada como con los objetos Java. Sin presionar la interfaz de herramientas o similar, no puede eliminar clases individuales.
Como siempre, puede tener pérdidas de memoria. Cualquier referencia fuerte a una de sus clases o cargador de clases filtrará todo. Esto ocurre con las implementaciones Sun de ThreadLocal, java.sql.DriverManager y java.beans, por ejemplo.
fuente
Si está viendo en vivo si la clase de descarga funcionó en JConsole o algo así, intente también agregar
java.lang.System.gc()
al final de la lógica de descarga de su clase. Se activa explícitamente el recolector de basura.fuente