Ich weiß, dass das Thema schon oft angesprochen und erklärt wurde und die SF von dem Forum, sowie google hab ich schon verwendet, aber dennoch komme ich nicht weiter...
Ich habe ein Programm, welches ich natürlich ab und an mal eine Aktualisierung unterziehe, ich aber keine Lust habe, meinen Bekannten/Freunden, die das Programm nutzen, immer wieder die neue jar-Datei zu schicken. Nun hätte ich gerne eine Update-Funktion geschrieben, wodurch ich das Programm während der Laufzeit aktualisiere und alle neuen Funktionen OHNE einen Neustart nutzbar machen möchte. Das dieses geht, ist mir bewusst, aber ich hab das Problem in der Umsetzung.
Ich lasse mein Programm auf einen Server zugreifen auf dem sich eine Textdatei befindet, worin steht, welche Versionsnummer momentan die aktuellste ist und die mit der vom Programm verglichen wird, ist die Versionsnummer in der txt-Datei höher, verbindet das Programm sich mit einem Server und lädt die aktuellste Datei herunter (die aktuelle Datei liegt im selben Pfad wie der Server). Das funktioniert soweit ganz gut. Diese landet dann auch ohne Probleme auf der Platte des Rechners. (Ist eine jar-Datei die geladen wird!)
Nun möchte ich die Klassen aus dem neuen jar in die momentan laufende Anwendung einbauen/laden und die neuen Funktionen nutzbar machen. Auch soll dann zum Beispiel die Versionsnummer erhöht werden, die sich in einer Config-Klasse befindet, aktualisiert werden.
Nun habe ich, wie schon oben erwähnt, viel recherchiert und weiß, dass ich die Klassen neu laden muss, am besten über einen eigenen Classloader bzw den URLClassLoader, um die alten zu ersetzen. Nun leitet der URLClassLoader die Anfrage erst an den ClassLoader, der schon meine Anwendung geladen hat weiter und es wird die Klasse nicht neu geladen. Mein Ziel ist es, dieselben Klassen mit der selben Package-Struktur aus der neuen Jar zu laden und die alten zu "ignorieren", damit der ClassLoader vom GC weggeräumt werden kann, doch kriege ich das nicht hin.
Mein Ansatz:
Hier habe ich es testweise erstmal mit einer einzigen Klasse versucht, die auch gefunden wird, aber nicht geladen wird, da diese schon im Parent-ClassLoader vorhanden ist und ich diesen leider nicht umgehen kann, zumindest mir nicht bewusst wie.
Es hieß immer, ich müsse einen neuen ClassLoader instanzieren und die neuen Klassen laden, sodass dadurch im Endeffekt die Referenz zum anderen ClassLoader "verloren" geht und der GC diesen wegräumt. Auch hieß es überall, dass die neu geladenen Klassen durch einen neuen ClassLoader einzigartig sind, dass heißt, dass diese auch im Parent-ClassLoader vorhanden sein können, ohne das Probleme auftreten.
Genau hier fängt mein Problem an. Ich müsste den Parent-ClassLoader umgehen oder zumindest meinen eigenen ClassLoader trotz der schon geladenen Klasse die Klasse neu laden können.
Weiterhin würde ich dann gerne wissen, wie ich es am schönsten schaffe, wenn alle Klassen neu geladen sind, OHNE ein Neustart der JVM, wie ich die GUI dann darauf aufmerksam mache, dass es sich mal aktualisieren/anpassen soll. Mir ist die Methode validate() bekannt, nur hat die neu geladene Klasse denn auch die gleiche Referenz auf dasselbe schon offene Fenster? Ich meine mal nicht.
Zumindest ist mir der obere Teil erstmal wichtiger und ich hoffe, ihr könnt mir helfen.
Ich habe ein Programm, welches ich natürlich ab und an mal eine Aktualisierung unterziehe, ich aber keine Lust habe, meinen Bekannten/Freunden, die das Programm nutzen, immer wieder die neue jar-Datei zu schicken. Nun hätte ich gerne eine Update-Funktion geschrieben, wodurch ich das Programm während der Laufzeit aktualisiere und alle neuen Funktionen OHNE einen Neustart nutzbar machen möchte. Das dieses geht, ist mir bewusst, aber ich hab das Problem in der Umsetzung.
Ich lasse mein Programm auf einen Server zugreifen auf dem sich eine Textdatei befindet, worin steht, welche Versionsnummer momentan die aktuellste ist und die mit der vom Programm verglichen wird, ist die Versionsnummer in der txt-Datei höher, verbindet das Programm sich mit einem Server und lädt die aktuellste Datei herunter (die aktuelle Datei liegt im selben Pfad wie der Server). Das funktioniert soweit ganz gut. Diese landet dann auch ohne Probleme auf der Platte des Rechners. (Ist eine jar-Datei die geladen wird!)
Nun möchte ich die Klassen aus dem neuen jar in die momentan laufende Anwendung einbauen/laden und die neuen Funktionen nutzbar machen. Auch soll dann zum Beispiel die Versionsnummer erhöht werden, die sich in einer Config-Klasse befindet, aktualisiert werden.
Nun habe ich, wie schon oben erwähnt, viel recherchiert und weiß, dass ich die Klassen neu laden muss, am besten über einen eigenen Classloader bzw den URLClassLoader, um die alten zu ersetzen. Nun leitet der URLClassLoader die Anfrage erst an den ClassLoader, der schon meine Anwendung geladen hat weiter und es wird die Klasse nicht neu geladen. Mein Ziel ist es, dieselben Klassen mit der selben Package-Struktur aus der neuen Jar zu laden und die alten zu "ignorieren", damit der ClassLoader vom GC weggeräumt werden kann, doch kriege ich das nicht hin.
Mein Ansatz:
Java:
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[] { new File(
Config.FILE_PLACE2).toURI().toURL() });
} catch (MalformedURLException e) {
e.printStackTrace();
}
Class<?> c = null;
try {
c = loader.loadClass("client.core.Main");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Hier habe ich es testweise erstmal mit einer einzigen Klasse versucht, die auch gefunden wird, aber nicht geladen wird, da diese schon im Parent-ClassLoader vorhanden ist und ich diesen leider nicht umgehen kann, zumindest mir nicht bewusst wie.
Es hieß immer, ich müsse einen neuen ClassLoader instanzieren und die neuen Klassen laden, sodass dadurch im Endeffekt die Referenz zum anderen ClassLoader "verloren" geht und der GC diesen wegräumt. Auch hieß es überall, dass die neu geladenen Klassen durch einen neuen ClassLoader einzigartig sind, dass heißt, dass diese auch im Parent-ClassLoader vorhanden sein können, ohne das Probleme auftreten.
Genau hier fängt mein Problem an. Ich müsste den Parent-ClassLoader umgehen oder zumindest meinen eigenen ClassLoader trotz der schon geladenen Klasse die Klasse neu laden können.
Weiterhin würde ich dann gerne wissen, wie ich es am schönsten schaffe, wenn alle Klassen neu geladen sind, OHNE ein Neustart der JVM, wie ich die GUI dann darauf aufmerksam mache, dass es sich mal aktualisieren/anpassen soll. Mir ist die Methode validate() bekannt, nur hat die neu geladene Klasse denn auch die gleiche Referenz auf dasselbe schon offene Fenster? Ich meine mal nicht.
Zumindest ist mir der obere Teil erstmal wichtiger und ich hoffe, ihr könnt mir helfen.