Redémarrer complètement un programme en Java ?
Fermé
TheKill_TnT
Messages postés
148
Date d'inscription
lundi 15 mai 2017
Statut
Membre
Dernière intervention
22 juin 2019
-
Modifié le 16 janv. 2019 à 13:59
KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 - 17 janv. 2019 à 12:35
KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 - 17 janv. 2019 à 12:35
A voir également:
- Redémarrer complètement un programme en Java ?
- Ce programme est écrit en python. il construit un mot secret dans une variable mais il ne l'affiche pas. modifiez-le pour qu'il affiche le mot secret. exécutez-le. quel est ce mot secret ? ✓ - Forum Python
- Redemarrer spooler impression - Guide
- Scanf en java ✓ - Forum Java
- Jeux java itel ✓ - Forum Jeux vidéo
- Frequence programme national ✓ - Forum Messagerie
1 réponse
KX
Messages postés
16668
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
17 mars 2023
3 005
16 janv. 2019 à 18:23
16 janv. 2019 à 18:23
Bonjour,
Pour aller plus loin tu pourrais utiliser des ClassLoader différents, un pour chaque version du programme.
La seule contrainte c'est que le loader doit être dans le ClassLoader système, il ne pourra donc pas être mis à jour.
Si je recompile Main avec "Hello 2" par exemple, le Loader me chargera bien la nouvelle classe, sans avoir à arrêter le programme Loader.
Pour aller plus loin tu pourrais utiliser des ClassLoader différents, un pour chaque version du programme.
La seule contrainte c'est que le loader doit être dans le ClassLoader système, il ne pourra donc pas être mis à jour.
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
public class Loader { // n'importe où sauf dans E:/Workspace/CCM/bin/
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
URL[] classUrls = { new URL("file:///E:/Workspace/CCM/bin/") };
System.out.println(Arrays.toString(classUrls));
try (URLClassLoader ucl = new URLClassLoader(classUrls)) {
System.out.println(ucl);
ucl.loadClass("Main").getMethod("main", String[].class).invoke(null, new Object[] { args });
Thread.sleep(2_000);
}
}
}
}
public class Main { // compilé dans E:/Workspace/CCM/bin/
public static void main(String[] args) {
System.out.println("Hello 1");
}
}
Si je recompile Main avec "Hello 2" par exemple, le Loader me chargera bien la nouvelle classe, sans avoir à arrêter le programme Loader.
17 janv. 2019 à 06:51
Moi j'aurais éventuellement pensé à une méthode qui exécute une ligne de commande ou directement un fichier, mais je vois pas où ça peut se trouver.
17 janv. 2019 à 08:04
L'idée serait : tu as un Jar que l'utilisateur démarre et dont le fonctionnement est le suivant.
Après il faudrait bien savoir quelles limites tu t'imposes pour "redémarrer" un programme.
S tu pars sur des lignes de commandes, tu n'auras pas un programme en exécution, mais plusieurs.
Avec les ClassLoader, tu auras toujours le même processus Java en exécution, même après "redémarrage".
Remarque : c'est le même principe de fonctionnement que les serveurs d'applications (Tomcat &co) qui vont démarrer/arrêter des war, mais le serveur en lui même reste ne s'arrête pas, ce qui lui permet d'arrêter certaines applications tout en laissant les autres démarrées.
17 janv. 2019 à 12:35
J'ai un projet C:/Workspace/ccm-Thread qui créé un thread-1.0-SNAPSHOT.jar avec le contenu suivant :
package ccm; public class MainThread extends Thread { @Override public void run() { for (int i = 0; !isInterrupted(); i++) { System.out.println(i); try { Thread.sleep(1_000); } catch (InterruptedException e) { return; } } } }J'ai un projet C:/Workspace/ccm-Loader qui créé un loader-1.0-SNAPSHOT.jar avec le contenu suivant :
package ccm; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; public class Loader { private static final Path HOME_LATEST = Paths.get("C:/Workspace/ccm-Loader/target/thread-local.jar"); private static final Path CLOUD_LATEST = Paths.get("C:/Workspace/ccm-Thread/target/thread-1.0-SNAPSHOT.jar"); public static void main(String[] args) { downloadLatestThreadJar(); Thread thread = loadLocalThreadJar("ccm.MainThread", args); thread.start(); try (Scanner sc = new Scanner(System.in)) { while (true) { sc.nextLine(); // Appuyer sur Entrée pour mettre à jour et redémarrer try { if (downloadLatestThreadJar()) { thread.interrupt(); thread.join(); thread = loadLocalThreadJar("ccm.MainThread", args); thread.start(); } } catch (Exception e) { Logger.getGlobal().log(Level.WARNING, "Can't update or restart", e); } } } } private static boolean downloadLatestThreadJar() { Logger.getGlobal().info("downloadLatestThreadJar: " + CLOUD_LATEST + " -> " + HOME_LATEST); try { HOME_LATEST.getParent().toFile().mkdirs(); Files.copy(CLOUD_LATEST, HOME_LATEST, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); Logger.getGlobal().info("downloadLatestThreadJar: success!"); return true; } catch (Exception e) { Logger.getGlobal().log(Level.WARNING, "Can't downloadLatestThreadJar", e); return false; } } private static Thread loadLocalThreadJar(String className, String[] args) { Logger.getGlobal().info("loadThreadJar: " + HOME_LATEST); try (URLClassLoader jcl = new URLClassLoader(new URL[] { HOME_LATEST.toUri().toURL() })) { @SuppressWarnings("unchecked") Class<Thread> threadClass = (Class<Thread>) jcl.loadClass(className); Thread thread = threadClass.newInstance(); thread.setName("Embedded " + className); thread.setContextClassLoader(jcl); Logger.getGlobal().info("loadLocalThreadJar: success!"); return thread; } catch (Exception e) { Logger.getGlobal().log(Level.WARNING, "Can't loadLocalThreadJar", e); return null; } } }Fonctionnement : on lance la commande
(Éventuellement on pourra configurer ccm.Loader comme Main-Class du Manifest)
Le Loader va prendre le fichier thread-1.0-SNAPSHOT.jar (on pourrait ici mettre en place un téléchargement du fichier sur le web par exemple) pour le copier dans thread-local.jar, le charger et exécuter ccm.MainThread
Dans la console du Loader on peut appuyer sur Entrée, ce qui va déclencher la mise à jour et le redémarrage du thread, sauf en cas d'erreur de mise à jour, dans ce cas on laisse la version précédente s'exécuter.