Oto test działania. Co 5 sekund Test.main() przeładowuje test.Test1.klasa z systemu plików i wywoł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);
}
}
}
Uruchom. Następnie zmień i ponownie skompiluj Test1
System.out.println("Hello !!!");
podczas testu. widać wyjście Test1.hello zmienił
...
Hello !
Hello !
Hello !!!
Hello !!!
ten sposób np Tomcat przeładowuje webapps. Ma osobną klasę ClassLoader dla każdej aplikacji internetowej i ładuje nową wersję w nowej klasie ClassLoader. Ten stary jest GCed, tak jak każdy obiekt Java, a także stare klasy.
Pamiętaj, że wczytaliśmy Test1 z TestClassLoader i wywołaliśmy jego pierwszą metodę z odbiciem. Ale wszystkie zależności Test1 będą domyślnie ładowane za pomocą programu ładującego klasy Test1, to znaczy, że wszystkie aplikacje Test1 będą ładowane przez JVM do TestClassLoader.
Dzięki za pomoc. Posiadanie nowej instancji modułu ładującego klasy dla każdego nowego ładowania klas, jak to tutaj zrobiono, rozwiązało problem. –