son - tipos de clases en java
¿Cómo reemplazar clases en una aplicación en ejecución en java? (5)
Digamos que tengo una clase llamada NameGenerator
. Puedo usar esto para generar nombres de acuerdo a una lógica dada. Luego escribo una clase TestNameGeneration
con un método que solicita una carta del usuario y genera un nombre de acuerdo. Ahora quiero cambiar la lógica en la clase NameGeneration
y aplicar ese cambio en particular sin detener la aplicación.
Hice esto para obtener más información sobre los cargadores de clases y, por favor, ¿alguien puede explicar los conceptos clave que tengo que aprender para hacer algo así o para encontrar referencias?
¿Qué pasa con un patrón de estrategia ? Podría ser una mejor solución para su problema en lugar de usar cargadores de clases.
Aquí hay una prueba de trabajo. Cada 5 segundos Test.main () vuelve a cargar test.Test1.class del sistema de archivos y llama a Test1.hello ()
package test;
public class Test1 {
public void hello() {
System.out.println("Hello !");
}
}
public class Test {
static class TestClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("test.Test1")) {
try {
InputStream is = Test.class.getClassLoader().getResourceAsStream("test/Test1.class");
byte[] buf = new byte[10000];
int len = is.read(buf);
return defineClass(name, buf, 0, len);
} catch (IOException e) {
throw new ClassNotFoundException("", e);
}
}
return getParent().loadClass(name);
}
}
public static void main(String[] args) throws Exception {
for (;;) {
Class cls = new TestClassLoader().loadClass("test.Test1");
Object obj = cls.newInstance();
cls.getMethod("hello").invoke(obj);
Thread.sleep(5000);
}
}
}
Ejecutarlo. Luego cambia y recompila Test1
System.out.println("Hello !!!");
mientras que la prueba se está ejecutando. Verá la salida de Test1.hello cambiado
...
Hello !
Hello !
Hello !!!
Hello !!!
Así es como, por ejemplo, Tomcat recarga webapps. Tiene un ClassLoader separado para cada aplicación web y carga una nueva versión en un nuevo ClassLoader. El anterior está diseñado como cualquier objeto de Java, así como las clases antiguas.
Tenga en cuenta que cargamos Test1 con TestClassLoader e invocamos su primer método con reflexión. Pero todas las dependencias de Test1 se cargarán implícitamente con el cargador de clases Test1, es decir, todas las aplicaciones de Test1 serán cargadas por JVM en TestClassLoader.
Es realmente simple, usará la ventaja de un OOP y la interfaz de uso, no necesita administrar el cargador de clases. Puede inyectar la implementación con un configurador:
Cree una interfaz llamada NameGeneration Cree n implementación NameGenerationImpl1, NameGenerationimpl2 por ejemplo En su clase de cliente, defina una variable:
NameGeneration nameGeneration ;
y el colocador:
public void setNameGeneration(NameGeneration nameGeneration) {
this.nameGeneration = nameGeneration ;
}
nameGeneration generará lo que quieras.
Cuando cambias el algoritmo, cambias la implementación haciendo, por ejemplo:
setNameGeneration(new NameGenerationImpl1()) ;
o
setNameGeneration(new NameGenerationImpl2()) ;
Hay 2 formas:
- Para sobrescribir el cargador de clases que está utilizando al usar primero el cargador de clases existente para arrancar su aplicación y específicamente para la clase que necesita para tener una actualización dinámica, debe usar el cargador de clases sobrescrito.
- Para utilizar el marco OSGi. Dependiendo de la escala de su aplicación, el marco OSGi puede no ser una buena opción ya que requiere que siga la convención de codificación.
Espero eso ayude
Puedes escribir tu propio cargador de clases personalizado. Cuando se produzcan cambios en el archivo de clase o recurso / jar que contiene el archivo de clase (verifique la marca de tiempo), destruya la instancia del cargador de clases anterior y cree una nueva instancia del cargador de clases que a su vez cargará el nuevo archivo de clases.