104 votes

Comment redémarrer une application Java ?

Comment puis-je redémarrer une application Java AWT ? J'ai un bouton auquel j'ai attaché un gestionnaire d'événements. Quel code dois-je utiliser pour redémarrer l'application ?

Je veux faire la même chose que Application.Restart() dans une application C#.

2 votes

Peut-être que je ne comprends pas votre question. Vous voulez que votre application ait un bouton qui redémarre l'application ? Donc, une fois que l'application n'est plus en cours d'exécution, elle devrait être capable de redémarrer elle-même ? Cela me semble impossible.

0 votes

Je ne demande pas qu'après l'arrêt de la JVM, je demande comment je peux faire renaître mon cadre java principal ?

2 votes

Pas impossible. Je vois le workbench eclipse redémarrer fréquemment, même Windows fait ce tour après les mises à jour. L'hypothèse fausse est que l'application est la seule chose en cours d'exécution, sans rien en dessous. Nous aurons besoin d'un lanceur capable de redémarrer, des tortues sur toute la ligne.

113voto

Veger Points 17657

Bien sûr, il est possible de redémarrer une application Java.

La méthode suivante montre un moyen de redémarrer une application Java :

public void restartApplication()
{
  final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
  final File currentJar = new File(MyClassInTheJar.class.getProtectionDomain().getCodeSource().getLocation().toURI());

  /* is it a jar file? */
  if(!currentJar.getName().endsWith(".jar"))
    return;

  /* Build command: java -jar application.jar */
  final ArrayList<String> command = new ArrayList<String>();
  command.add(javaBin);
  command.add("-jar");
  command.add(currentJar.getPath());

  final ProcessBuilder builder = new ProcessBuilder(command);
  builder.start();
  System.exit(0);
}

En gros, il fait ce qui suit :

  1. Trouvez l'exécutable java (j'ai utilisé le binaire java ici, mais cela dépend de vos besoins)
  2. Trouvez l'application (un jar dans mon cas, en utilisant la commande MyClassInTheJar pour trouver l'emplacement du jar lui-même)
  3. Construire une commande pour redémarrer le jar (en utilisant le binaire java dans ce cas)
  4. Exécutez-le ! (et ainsi mettre fin à l'application en cours et la relancer)

0 votes

Dans quel package se trouve UpdateReportElements ? Bizarrement, je ne trouve pas cette information via Google.

0 votes

Ah, ça ne fait rien, c'est la classe de @Veger. un substitut pour votre propre classe principale, je suppose ?

0 votes

@ericsoco Oui peut être n'importe quelle classe, elle est utilisée pour trouver l'emplacement du fichier jar. Qui est utilisé pour redémarrer l'application. Je vais mettre à jour la réponse pour la rendre plus claire !

35voto

Meinersbur Points 3511
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;

public class Main {
    public static void main(String[] args) throws IOException, InterruptedException {
        StringBuilder cmd = new StringBuilder();
        cmd.append(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java ");
        for (String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
            cmd.append(jvmArg + " ");
        }
        cmd.append("-cp ").append(ManagementFactory.getRuntimeMXBean().getClassPath()).append(" ");
        cmd.append(Main.class.getName()).append(" ");
        for (String arg : args) {
            cmd.append(arg).append(" ");
        }
        Runtime.getRuntime().exec(cmd.toString());
        System.exit(0);
    }
}

Dédié à tous ceux qui disent que c'est impossible.

Ce programme recueille toutes les informations disponibles pour reconstituer la ligne de commande originale. Ensuite, il la lance et comme il s'agit de la même commande, votre application démarre une seconde fois. Ensuite, nous quittons le programme original, le programme enfant reste en cours d'exécution (même sous Linux) et fait exactement la même chose.

AVERTISSEMENT : Si vous exécutez ce programme, sachez qu'il ne cesse de créer de nouveaux processus, comme le fait une bombe à fourche .

1 votes

Amélioration possible ManagementFactory.getRuntimeMXBean().getInputArguments() ne vous donnera que les arguments d'entrée passés à la JVM. Il manque les paramètres passés à votre application. ex, java -jar start.jar -MISSED_PARAM=true . Sur un jvm oracle, vous pouvez récupérer ces paramètres en utilisant System.getProperty("sun.java.command") .

3 votes

La VM parent pourrait s'arrêter si la VM enfant et la VM parent n'étaient pas connectées l'une à l'autre par des tuyaux, ce qui est le cas lorsque la VM enfant est lancée. En utilisant ProcessBuilder y inheritIO() la VM enfant peut être démarrée de la même manière que la VM parent se termine.

1 votes

J'ai une version de ça en cours. Ce commentaire est pour vous dire comment l'arrêter : renommez quelque chose dans le chemin qui contient le java.exe.

31voto

aioobe Points 158466

En gros, vous ne pouvez pas. Du moins pas de manière fiable. Cependant, vous ne devriez pas en avoir besoin.

En ne peut pas partie

Pour redémarrer un programme Java, vous devez redémarrer la JVM. Pour redémarrer la JVM, vous devez

  1. Localisez le java qui a été utilisé. Vous pouvez essayer avec System.getProperty("java.home") mais il n'y a aucune garantie qu'il pointe vers le lanceur qui a été utilisé pour lancer votre application. (La valeur renvoyée peut ne pas pointer vers le JRE utilisé pour lancer l'application. ou il aurait pu être remplacé par -Djava.home .)

  2. Vous voudrez sans doute respecter les paramètres de mémoire d'origine, etc. -Xmx , -Xms ), vous devez donc déterminer quels paramètres ont été utilisés pour démarrer la première JVM. Vous pouvez essayer d'utiliser ManagementFactory.getRuntimeMXBean().getInputArguments() mais il n'y a aucune garantie que cela reflète les paramètres utilisés. Cela est même précisé dans la documentation de cette méthode :

    En général, toutes les options de la ligne de commande de la commande 'java' ne sont pas transmises à la machine virtuelle Java. Ainsi, les arguments d'entrée renvoyés peuvent ne pas inclure toutes les options de la ligne de commande.

  3. Si votre programme lit les entrées de Standard.in le stdin original sera perdu lors du redémarrage.

  4. Beaucoup de ces trucs et astuces échoueront en présence d'une SecurityManager .

En ne devrait pas avoir besoin partie

Je vous recommande de concevoir votre application de manière à ce qu'il soit facile de tout nettoyer, puis de créer une nouvelle instance de votre classe "main".

De nombreuses applications sont conçues pour ne rien faire d'autre que de créer une instance dans la méthode principale :

public class MainClass {
    ...
    public static void main(String[] args) {
        new MainClass().launch();
    }
    ...
}

En utilisant ce modèle, il devrait être assez facile de faire quelque chose comme.. :

public class MainClass {
    ...
    public static void main(String[] args) {
        boolean restart;
        do {
            restart = new MainClass().launch();
        } while (restart);
    }
    ...
}

et laissez launch() retourne vrai si et seulement si l'application a été fermée d'une manière telle qu'elle doit être redémarrée.

3 votes

+1 pour de meilleurs conseils de conception ; bien que, parfois, ce n'est tout simplement pas possible, surtout si vous utilisez JNI, par exemple.

0 votes

Eh bien, une bibliothèque native pourrait modifier l'état global qui ne peut pas être modifié à partir de l'interface JNI, il n'y aurait donc aucun moyen de "redémarrer" l'état du programme autrement qu'en redémarrant le processus. Bien sûr, la bibliothèque native devrait être mieux conçue, mais parfois vous dépendez de choses que vous ne pouvez pas contrôler.

0 votes

D'accord, mais avec ce raisonnement, vous pouvez tout aussi bien avoir une bibliothèque Java pure qui modifie certaines variables statiques internes. Ce serait cependant un défaut de conception et cela ne devrait pas se produire dans des bibliothèques bien écrites.

13voto

maerics Points 47743

À proprement parler, un programme Java ne peut pas se relancer lui-même, car il doit tuer la JVM dans laquelle il s'exécute, puis la relancer, mais une fois que la JVM n'est plus en cours d'exécution (tuée), aucune action ne peut être entreprise.

Vous pourriez faire quelques tours de passe-passe avec des classloaders personnalisés pour charger, emballer et relancer les composants AWT, mais cela risque de causer de nombreux maux de tête en ce qui concerne la boucle d'événements de l'interface graphique.

Selon la façon dont l'application est lancée, vous pourriez lancer la JVM dans un script enveloppant qui contient une boucle do/while, qui continue jusqu'à ce que la JVM sorte avec un code particulier, alors l'application AWT devrait appeler System.exit(RESTART_CODE) . Par exemple, en pseudo-code de script :

DO
  # Launch the awt program
  EXIT_CODE = # Get the exit code of the last process
WHILE (EXIT_CODE == RESTART_CODE)

L'application AWT devrait quitter la JVM avec autre chose que le RESTART_CODE lors d'une terminaison "normale" qui ne nécessite pas de redémarrage.

0 votes

Solution très intéressante. Le problème sous OSX est que, typiquement, les applications Java sont exécutées à partir d'un fichier compilé. JavaApplicationStub ... Pas sûr qu'il y ait un moyen facile de contourner cela.

0 votes

J'ai fait cela sous Windows et cela fonctionne parfaitement bien, j'ai un batch script qui lance initialement mon programme en faisant java my-program.java et la dernière ligne du fichier batch est if "%ERRORLEVEL%" EQU "1" java my-program.java donc si mon programme se termine avec System.exit(1) il redémarre, sinon System.exit(0) le fait s'arrêter. Bien que j'aie été capable de le faire en utilisant du java pur auparavant (en ajoutant un crochet d'arrêt + en utilisant processbuilder.inheritIO() pour que stdin/out soit passé au nouveau processus) ; cette approche est beaucoup plus facile.

7voto

whatnick Points 3339

Eclipse redémarre généralement après l'installation d'un plugin. Pour ce faire, il utilise un wrapper eclipse.exe (application de lancement) pour Windows. Cette application exécute le noyau eclipse runner jar et si l'application eclipse java se termine avec un code de relance, eclipse.exe redémarre le workbench. Vous pouvez construire un bout de code natif similaire, un shell script ou un autre wrapper de code java pour réaliser le redémarrage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X