¿Descargar clases en java?
Tengo un cargador de clases personalizado para que una aplicación de escritorio pueda comenzar a cargar clases dinámicamente desde un servidor de aplicaciones con el que necesito hablar. Hicimos esto porque la cantidad de frascos que se requieren 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 encontrarme con un problema en el que necesito hablar con dos servidores de aplicaciones diferentes y descubrí que, dependiendo de qué clases cargue primero, podría fallar gravemente... ¿Hay alguna manera de forzar la descarga de la clase sin matar realmente la JVM?
Espero que esto tenga sentido
La única forma de descargar una clase es si el cargador de clases utilizado se recolecta como basura. Esto significa que las referencias a cada clase y al propio 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 clases a cargadores de clases Jar específicos. De esa manera, puede señalar diferentes versiones del archivo jar para cada servidor de aplicaciones.
Sin embargo, esto no es trivial. La plataforma OSGi se esfuerza por hacer precisamente 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 posible implementación podría ser utilizar una instancia de la clase JarClassloader para cada archivo JAR.
Y cree una nueva clase MultiClassloader que extienda 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 genere una excepción 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 necesites escribir la tuya propia.
Si instancias 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 debían cargarse y descargarse de la memoria y funcionó bastante bien.
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 a los cargadores superiores. .
Una clase se define por su paquete, su nombre y el cargador de clases que cargó originalmente. Programar un cargador de clases "proxy" que es el primero que se carga al iniciar la JVM. Flujo de trabajo:
- El programa se inicia y este cargador de clases proxy carga la clase "principal" real.
- 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
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). - Para cada clase que sea reemplazable, cree una instancia de un cargador de clases (que realmente carga la clase y no la delega al cargador de clases principal) y cárguelo 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 para una clase que se cargó antes, devuelve la clase del cargador de clases almacenado antes.
- Debería ser suficiente ubicar la matriz de bytes de una clase mediante su cargador de clases (o "eliminar" el par clave/valor de su estructura de datos) y recargar la clase en caso de que desee cambiarla.
Si se hace correctamente, no debería aparecer 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 "Programación Java basada en servidor" de 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 realizar GC en el cargador de clases. Cargador de clases de tarro
Los cargadores de clases pueden ser un problema complicado. Puede tener problemas especialmente si utiliza varios cargadores de clases y no tiene sus interacciones clara y rigurosamente definidas. Creo que para poder descargar una clase tendrás que eliminar todas las referencias a cualquier clase (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 liviano y fácil de usar.