2009-04-08 5 views
11

Estoy escribiendo un programa de servidor que se utiliza para ejecutar pruebas unitarias de una API (que muestra una gran cantidad de información y proporcionar acceso a la web para controlar /monitorear toda la cosa) ...¿Puedo descargar y volver a cargar dinámicamente (otras versiones del mismo) JAR?

Esta API es conocido por el servidor durante el tiempo de compilación y se proporciona como un JAR.

Para poder comparar entre los resultados de los exámenes de unidad de versiones diferentes de la API (sin necesidad de reiniciar el servidor), Quiero ser capaz de descargar la versión 'actual' de la API, y para recargar uno más nuevo (o uno más antiguo).

no quiero utilizar URLClassLoader e invocar cada método por su nombre
(usando getDeclaredMethod("someMethod")),
porque el servidor depende en gran medida de la API y sería complicado para 'envoltura' cada método de llamada de esa manera sucia.

que estaba pensando: Dado que todas las interfaces de todos los versiones del JAR son misma, podría no lo hago por una recarga de alguna manera otra versión del JAR (sin ese nombre, por invocación-?)

Nota: Estoy utilizando la última versión de Java SE (6) y Java EE (5).

Si cree que lo que intento lograr no es posible, sugiera una "solución" o un concepto diferente.

+0

Véase también: http://stackoverflow.com/questions/148681/unloading-classes-in-java – sleske

Respuesta

7

creo que si se carga una clase usando

Class.forName(clsname, init, classloader); 

(Javadoc aquí) obtendrá una instancia de la clase proporcionada por el cargador de clase dada. Todo lo cargado a causa de esa clase también se cargará a través del mismo cargador de clases.

Siempre que tenga mucho cuidado con los objetos instanciados a partir de este punto (para permitir GC), podrá volver a cargar versiones diferentes. Ya lo hice una vez con Java 1.3, me tomó mucha depuración, pero al final tuve una aplicación "bootstrap" que cargó una clase Runnable por nombre y fue capaz de "reiniciar suavemente" creando una instancia de un nuevo cargador de clases contra un URL diferente y yendo de nuevo.

-2

Probablemente no. El cargador de clases de Java realmente no es compatible con la carga en tiempo de ejecución; incluso los classloaders disponibles son hacks que usan un objeto proxy.

1

OSGi es un marco que le permitirá hacerlo. JSR 277 the Java Module System está diseñado para hacer eso también (creo). No he seguido el debate OSGi -vs-JSR 277, así que no sé si están tratando de marginarlos del todo.

Puede rodar por sí mismo con los cargadores de clase, pero será menos "divertido".

0

Sí. Lo he visto hecho en una conferencia NFJS.Es la forma en que cosas como los contenedores web admiten la implementación rápida de aplicaciones e implica aprovechar el alcance de los cargadores de clase. Para lograrlo, necesitas crear un nuevo cargador de clases y usarlo para cargar la biblioteca en cuestión ... luego descarta el cargador (o no) y crea otro cuando quieras volver a cargarlo. También es posible que tenga que anular el comportamiento del cargador de clases (recuerdo algo sobre los cargadores de clases que reciben clases a través de sus padres primero de manera predeterminada). Además, recuerdo una advertencia de que los objetos creados por diferentes cargadores de clases son no compatibles con (no de el mismo tipo) entre sí incluso si el archivo .class es exactamente el mismo.

Sin embargo, es principalmente deep magic. ;-)

4

Puede modificar programáticamente su classpath para reflejar sus cambios en el JAR. Aquí es cómo lo haría:

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
     Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); 
     m.setAccessible(true); 
     m.invoke(urlClassLoader, jarFile.toURI().toURL()); 
     String cp = System.getProperty("java.class.path"); 
     if (cp != null) { 
      cp += File.pathSeparatorChar + jarFile.getCanonicalPath(); 
     } else { 
      cp = jarFile.toURI().getPath(); 
     } 
     System.setProperty("java.class.path", cp); 

donde archivoJar es la versión de la jarra que desea utilizar/sobrescribir.

3

Puede usar el paquete de código abierto: JclLoader que ayuda a cargar diferentes versiones del mismo contenedor. Esta era también una necesidad en uno de nuestros sistemas para hacer pruebas.

Enlace: http://sourceforge.net/projects/jcloader/

+0

lo uso. Funciona, una nota: si quieres volver a cargar la clase, deberías hacerlo con una instancia diferente de JarClassLoader. Si lo pruebas con el mismo error de cargador de clases, simplemente crea otro. – odiszapc

+0

He intentado con muchas soluciones ... Puedo confirmar, esta es la solución más simple y elegante que pude encontrar para la carga dinámica de clases. Esta realmente debería ser la respuesta aceptada. – taylorcressy

Cuestiones relacionadas