Ecco un test di funzionamento. Ogni 5 secondi Test.main() ricarica test.Test1.classe dal file system e chiama 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);
}
}
}
Eseguirlo. Quindi modificare e ricompilare Test1
System.out.println("Hello !!!");
mentre Test è in esecuzione. Vedrete uscita Test1.hello cambiato
...
Hello !
Hello !
Hello !!!
Hello !!!
Ecco come ad esempio Tomcat ricarica webapps. Ha un ClassLoader separato per ogni webapp e carica una nuova versione in un nuovo ClassLoader. Quello vecchio è GCed proprio come qualsiasi oggetto Java e anche le vecchie classi.
Nota che abbiamo caricato Test1 con TestClassLoader e invocato il suo primo metodo con reflection. Ma tutte le dipendenze Test1 verranno caricate implicitamente con il caricatore di classe Test1, ovvero tutte le applicazioni Test1 verranno caricate da JVM in TestClassLoader.
fonte
2013-01-14 11:21:17
Grazie per l'aiuto. Avere una nuova istanza del caricatore di classe per ogni nuova classe di caricamento, come hai fatto qui risolto il problema. –