Pregunta

Tengo un cargador de clases personalizado para que una aplicación de escritorio pueda comenzar a cargar clases dinámicamente 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, acabo de encontrar 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

¿Fue útil?

Solución

La única forma en que se puede descargar una Clase es si el cargador de clases usado es la 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 Classloader para cada archivo jar, y un Classloader para cada uno de los AppServers 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.

Esto no es trivial, sin embargo. La plataforma OSGi se esfuerza por hacer precisamente 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 usar OSGI, una implementación posible podría ser usar una instancia de JarClassloader clase para cada archivo JAR.

Y crea 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 pueda encontrar una definición, o se lance 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 la suya.

Si crea una instancia de MultiClassloader para cada conexión al servidor, en principio es posible que cada servidor use una versión diferente de la misma clase.

He utilizado 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 funcionó bastante bien.

Otros consejos

Sí, hay formas de cargar clases y de " descargar " ellos mas tarde 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. Programa un " proxy " cargador de clases, que es el primero que se carga al iniciar la JVM. Flujo de trabajo:

  • El programa se inicia y el " main " -class se carga con este cargador de clases proxy.
  • Cada clase que normalmente se carga (es decir, no a través de otra implementación del 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 (estos no deben cargarse a través de ningún otro cargador de clases que no sea el cargador de clases del sistema).
  • Para cada clase reemplazable, crea una instancia de un cargador de clases (que realmente carga la clase y no lo delega al cargador de clases padre) y cárgalo a través de esto.
  • 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 cargador de clases proxy recibe una solicitud de una clase que se cargó antes, devuelve la clase del cargador de clases almacenado anteriormente.
  • Debería ser suficiente ubicar la matriz de bytes de una clase por su cargador de clases (o '' eliminar '' el par clave / valor de su estructura de datos) y volver a cargar la clase en caso de que desee cambiarla.

Hecho aquí, no debería aparecer una ClassCastException o LinkageError etc.

Para obtener más información acerca de las jerarquías de cargadores de clases (sí, eso es exactamente lo que está implementando aquí; -) mire " ; Programación Java basada en servidor " por Ted Neward : ese libro me ayudó a implementar algo muy similar a lo que quieres.

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

Los cargadores de clases pueden ser un problema complicado. Especialmente puede tener problemas si está utilizando múltiples cargadores de clases y no tiene sus interacciones definidas de manera clara y rigurosa. Creo que para poder 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 utilizando OSGi . OSGi es realmente potente y sorprendentemente ligero y fácil de usar,

Puedes descargar un ClassLoader pero no puedes 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 tu propio ClassLoader para que puedas descargar.

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

Como siempre puedes tener fugas 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.

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 el recolector de basura.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top