Reiniciar por completo un programa en Java?
TheKill_TnT
Mensajes publicados
172
Estado
Miembro
-
KX Mensajes publicados 19031 Estado Moderador -
KX Mensajes publicados 19031 Estado Moderador -
Hola,
Mi pregunta es la siguiente: ¿Cómo reiniciar completamente un programa Java Runtime Environment?
Ya hice una pregunta similar, pero no llegaba hasta ahí. Aquí, me gustaría reiniciar un programa para actualizarlo (se ha descargado de nuevo y la idea es aplicar la actualización).
Teóricamente sería posible con la ayuda de un segundo programa Java (que serviría entonces como instanciador), pero no sé cómo hacerlo.
La idea sería tener algo como esto:
Y así que nuestro updater.jar esté hecho de:
Y de esta manera finalizar la actualización.
¡Gracias de antemano!
Configuración: Windows / Chrome 71.0.3578.98, Java Development Kit 8
Mi pregunta es la siguiente: ¿Cómo reiniciar completamente un programa Java Runtime Environment?
Ya hice una pregunta similar, pero no llegaba hasta ahí. Aquí, me gustaría reiniciar un programa para actualizarlo (se ha descargado de nuevo y la idea es aplicar la actualización).
Teóricamente sería posible con la ayuda de un segundo programa Java (que serviría entonces como instanciador), pero no sé cómo hacerlo.
La idea sería tener algo como esto:
public void reiniciar(){ Algo.AutreChose(new File("updater.jar")) //Instanciar un archivo JAR } Y así que nuestro updater.jar esté hecho de:
public static void main(String[] args){ //supongamos que todo esto está dentro de try catch ¿eh? File f = new File("programme_update.jar") Algo.AutreChose(f, "programme.jar") //Renombrar el archivo descargado a "programme.jar" Algo.AutreChose(f) //Otra vez instanciar un archivo JAR } Y de esta manera finalizar la actualización.
¡Gracias de antemano!
Configuración: Windows / Chrome 71.0.3578.98, Java Development Kit 8
1 respuesta
Hola,
Para ir más allá podrías usar diferentes ClassLoaders, uno para cada versión del programa. La única constraint es que el loader debe estar en el ClassLoader del sistema, por lo que no podrá ser actualizado.
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 reclasificas Main con "Hello 2" par exemple, el Loader cargará bien la nueva clase, sin tener que detener el programa Loader.
--
La confianza no excluye el control
Yo, eventualmente, habría pensado en un método que ejecute una línea de comandos o directamente un archivo, pero no veo dónde podría ubicarse.
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.
Tengo un proyecto C:/Workspace/ccm-Thread que crea un thread-1.0-SNAPSHOT.jar con el contenido siguiente :
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; } } } }Tengo un proyecto C:/Workspace/ccm-Loader que crea un loader-1.0-SNAPSHOT.jar con el contenido siguiente :
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; } } }Función: se ejecuta la commande
(Eventualmente se podrá configurar ccm.Loader como Main-Class del Manifest)
El Loader va a tomar el archivo thread-1.0-SNAPSHOT.jar (aquí se podría implementar una descarga del archivo desde la web, por ejemplo) para copiarlo en thread-local.jar, cargarlo y ejecutar ccm.MainThread
En la consola del Loader se puede pulsar Enter, lo que disparará la actualización y el reinicio del thread, salvo en caso de error de actualización; en ese caso se deja ejecutar la versión anterior.