¿Descargar clases en java?

Tengo un cargador de clases personalizado para que una aplicación de escritorio pueda comenzar dinámicamente a cargar clases desde un AppServer con el que necesito hablar. Hicimos esto porque la cantidad de flasks que se requieren para hacer esto es ridícula (si queríamos 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, acabo de encontrar un problema en el que necesito hablar con dos AppServers diferentes y descubrí que, dependiendo de las clases que cargue primero, es posible que rompa mal … ¿Hay alguna forma de forzar la descarga de la clase sin matar realmente a la JVM?

Espero que esto tenga sentido

La única manera de descargar una clase es si el cargador de clases usado es basura. Esto significa que las referencias a cada clase y al cargador de clases 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 delega la carga real de las clases en los cargadores de clases Jar específicos. De esta forma, puede señalar diferentes versiones del archivo jar para cada servidor de aplicaciones.

Esto no es trivial, sin embargo. La plataforma OSGi se esfuerza por hacer justamente esto, ya que cada paquete tiene un cargador de clases diferente y la plataforma resuelve las dependencias. Quizás una buena solución sería echarle un vistazo.

Si no desea utilizar OSGI, una implementación posible 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 clases internos hasta que se encuentre una definición, o se genere 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 las suyas propias.

Si crea 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 tuvieron que cargarse y descargarse de la memoria y funcionó bastante bien.

Sí, hay formas de cargar clases y “descargarlas” más adelante. El truco es 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 clase que cargó originalmente. Programe un cargador de clases “proxy” que es el primero que se carga al iniciar la JVM. Flujo de trabajo:

  • El progtwig comienza y la clase real “principal” es cargada por este cargador de clases proxy.
  • Cada clase que luego se carga normalmente (es decir, no a través de otra implementación de cargador de clases que podría romper la jerarquía) se delegará a este cargador de clases.
  • El cargador de clases proxy delega java.x y sun.x al cargador de clases del sistema ( no se deben cargar a través de ningún otro cargador de clases que el cargador de clases del sistema).
  • Para cada clase que es reemplazable, cree una instancia de un cargador de clases (que realmente carga la clase y no lo delegue en el cargador de clases principal) y cárguelo a través de este.
  • Almacene el paquete / nombre de las clases como claves y el cargador de clases como valores en una estructura de datos (es decir, Hashmap).
  • Cada vez que el clasificador de proxy obtiene una solicitud para una clase que se cargó antes, devuelve la clase del cargador de clases almacenado anteriormente.
  • Debería ser suficiente para ubicar el conjunto de bytes de una clase por su cargador de clases (o para “eliminar” el par clave / valor de su estructura de datos) y volver a cargar la clase en caso de que quiera cambiarla.

Hecho allí no debería venir una ClassCastException o LinkageError, etc.

Para obtener más información sobre las jerarquías del cargador de clases (sí, eso es exactamente lo que está implementando aquí; -) consulte “Progtwigción Java basada en servidor” por Ted Neward , ese libro me ayudó a implementar algo muy similar a lo que desea.

Escribí un cargador de clases personalizado, desde el cual es posible descargar clases individuales sin GC el cargador de clases. Jar Class Loader

Los cargadores de clases pueden ser un problema complicado. En especial, puede tener problemas si usa varios cargadores de clases y no tiene sus interacciones definidas de forma clara y rigurosa. Creo que para poder descargar realmente una clase, tendrás que eliminar todas las referencias a las clases (y sus instancias) que estás intentando 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,

Puede descargar un ClassLoader pero no puede descargar clases específicas. Más específicamente, no puede descargar las clases creadas en un ClassLoader que no está bajo su control.

Si es posible, sugiero usar su propio ClassLoader para que pueda descargar.

Las clases tienen una referencia fuerte implícita a su instancia de ClassLoader, y viceversa. Son basura recolectada como con objetos Java. Sin tocar la interfaz de herramientas o similar, no puede eliminar clases individuales.

Como siempre, puedes tener pérdidas de memoria. Cualquier referencia fuerte a una de tus clases o cargador de clases perderá todo. Esto ocurre con las implementaciones de Sun de ThreadLocal, java.sql.DriverManager y java.beans, por ejemplo.

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. Activa explícitamente Garbage Collector.