Как перезапустить приложение Java?

Как перезапустить приложение Java AWT? У меня есть кнопка, к которой я привязал обработчик событий. Какой код следует использовать для перезапуска приложения?

Я хочу сделать то же самое, что Application.Restart() делать в приложении С#.

Ответ 1

Конечно, можно перезапустить Java-приложение.

Следующий способ показывает способ перезапуска приложения 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);
}

В основном это делает следующее:

  • Найти исполняемый файл java (здесь я использовал двоичный код java, но это зависит от ваших требований)
  • Найти приложение (банку в моем случае, используя класс MyClassInTheJar, чтобы найти местоположение jar)
  • Создайте команду для перезапуска jar (используя двоичный код java в этом случае)
  • Выполните его! (и, таким образом, завершение текущего приложения и его запуск снова)

Ответ 2

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);
    }
}

Посвящается всем тем, кто говорит, что это невозможно.

Эта программа собирает всю информацию, доступную для восстановления исходной командной строки. Затем он запускает его, и поскольку он является той же самой командой, ваше приложение запускается во второй раз. Затем мы выходим из исходной программы, дочерняя программа продолжает работать (даже под Linux) и делает то же самое.

ПРЕДУПРЕЖДЕНИЕ. Если вы запустите это, имейте в виду, что он никогда не заканчивает создание новых процессов, подобно fork bomb.

Ответ 3

В принципе, вы не можете. По крайней мере, не на надежном пути.

Чтобы перезапустить Java-программу, вам необходимо перезапустить JVM. Чтобы перезапустить JVM, вам необходимо

  • Найдите используемую пусковую установку java. Вы можете попробовать с помощью System.getProperty("java.home"), но нет гарантии, что это фактически укажет на панель запуска, которая была использована для запуска вашего приложения. (Возвращаемое значение может не указывать на JRE, используемое для запуска приложения, или оно могло быть переопределено -Djava.home.)

  • Предположительно вы хотели бы почтить исходные настройки памяти и т.д. (-Xmx, -Xms, & hellip;), поэтому вам нужно выяснить, какие настройки используются для запуска первой JVM. Вы можете попробовать использовать ManagementFactory.getRuntimeMXBean().getInputArguments(), но нет гарантии, что это отразит используемые настройки. Это даже указано в документации этого метода:

    Как правило, не все параметры командной строки для команды "java" передаются на виртуальную машину Java. Таким образом, возвращаемые входные аргументы могут не включать все параметры командной строки.

  • Если ваша программа считывает ввод с Standard.in, исходный stdin будет потерян при перезагрузке.

  • Многие из этих трюков и хаков будут терпеть неудачу при наличии SecurityManager.


С другой стороны: Вам не нужно.

Я рекомендую вам разработать ваше приложение, чтобы было легко чистить все, и после этого создать новый экземпляр вашего "основного" класса.

Многие приложения предназначены только для создания экземпляра в основном методе:

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

Используя этот шаблон, должно быть достаточно легко сделать что-то вроде:

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

и пусть launch() возвращает true тогда и только тогда, когда приложение было отключено таким образом, что его необходимо перезапустить.

Ответ 4

Строго говоря, Java-программа не может перезапускаться сама, так как для этого необходимо убить JVM, в которой она запущена, а затем запустить ее снова, но как только JVM больше не будет запущен (убит), никакие действия не могут быть предприняты.

Вы можете сделать некоторые трюки с пользовательскими загрузчиками классов для загрузки, упаковки и запуска компонентов AWT, но это, вероятно, вызовет много головных болей в отношении цикла событий GUI.

В зависимости от того, как приложение запускается, вы можете запустить JVM в оболочке script, которая содержит цикл do/while, который продолжается, пока JVM выходит с определенным кодом, тогда приложение AWT должно было бы вызвать System.exit(RESTART_CODE). Например, в сценарии псевдокода:

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

Приложение AWT должно выйти из JVM с чем-то, отличным от RESTART_CODE, при "нормальном" завершении, которое не требует перезапуска.

Ответ 5

Eclipse обычно перезапускается после установки плагина. Они делают это, используя оболочку eclipse.exe(приложение запуска) для окон. Это приложение запускает ядро ​​ядра eclipse runner, и если приложение java eclipse завершается с помощью перезапуска кода, eclipse.exe перезапускает верстак. Вы можете создать аналогичный бит собственного кода, оболочки script или другой оболочки Java-кода для достижения перезапуска.

Ответ 6

Если вам действительно нужно перезагрузить приложение, вы можете написать отдельное приложение, чтобы запустить его...

Эта страница содержит множество различных примеров для разных сценариев:

http://www.rgagnon.com/javadetails/java-0014.html

Ответ 7

Несмотря на то, что этот вопрос старен и отвечает, я наткнулся на проблему с некоторыми решениями и решил добавить мое предложение в микс.

Проблема с некоторыми решениями заключается в том, что они строят одну командную строку. Это создает проблемы, когда некоторые параметры содержат пробелы, особенно java.home.

Например, в окнах строка

final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";

Может получиться что-то вроде этого: C:\Program Files\Java\jre7\bin\java

Эта строка должна быть заключена в кавычки или экранирована из-за пробела в Program Files. Не большая проблема, но несколько раздражающая и подверженная ошибкам, особенно в кросс-платформенных приложениях.

Поэтому мое решение создает команду как массив команд:

public static void restart(String[] args) {

        ArrayList<String> commands = new ArrayList<String>(4 + jvmArgs.size() + args.length);
        List<String> jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();

        // Java
        commands.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");

        // Jvm arguments
        for (String jvmArg : jvmArgs) {
            commands.add(jvmArg);
        }

        // Classpath
        commands.add("-cp");
        commands.add(ManagementFactory.getRuntimeMXBean().getClassPath());

        // Class to be executed
        commands.add(BGAgent.class.getName());

        // Command line arguments
        for (String arg : args) {
            commands.add(arg);
        }

        File workingDir = null; // Null working dir means that the child uses the same working directory

        String[] env = null; // Null env means that the child uses the same environment

        String[] commandArray = new String[commands.size()];
        commandArray = commands.toArray(commandArray);

        try {
            Runtime.getRuntime().exec(commandArray, env, workingDir);
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Ответ 8

Я сам изучал этот вопрос, когда наткнулся на этот вопрос.

Независимо от того, что ответ уже принят, я все же хотел бы предложить альтернативный подход для полноты. В частности, Apache Ant служил очень гибким решением.

В принципе, все сводится к файлу Ant script с одной задачей выполнения Java (см. здесь и здесь), вызывается из кода Java (см. here). Этот Java-код, который может быть запуском метода, может быть частью приложения, которое необходимо перезапустить. Приложение должно иметь зависимость от библиотеки Apache Ant (jar).

Когда приложение необходимо перезапустить, он должен вызывать метод запуска и выхода из виртуальной машины. Задача Ant java должна иметь параметры fork и spawn, установленные в true.

Вот пример Ant script:

<project name="applaucher" default="launch" basedir=".">
<target name="launch">
    <java classname="package.MasinClass" fork="true" spawn="true">
        <jvmarg value="-splash:splash.jpg"/>
        <jvmarg value="-D other VM params"/>
        <classpath>
            <pathelement location="lib-1.jar" />
            ...
            <pathelement location="lib-n.jar" />
        </classpath>
    </java>
</target>
</project>

Код метода запуска может выглядеть примерно так:

public final void launch(final String antScriptFile) {
 /* configure Ant and execute the task */
   final File buildFile = new File(antScriptFile);
   final Project p = new Project();
   p.setUserProperty("ant.file", buildFile.getAbsolutePath());

   final DefaultLogger consoleLogger = new DefaultLogger();
   consoleLogger.setErrorPrintStream(System.err);
   consoleLogger.setOutputPrintStream(System.out);
   consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
   p.addBuildListener(consoleLogger);

   try {
       p.fireBuildStarted();
       p.init();
       final ProjectHelper helper = ProjectHelper.getProjectHelper();
       p.addReference("ant.projectHelper", helper);
       helper.parse(p, buildFile);
       p.executeTarget(p.getDefaultTarget());
       p.fireBuildFinished(null);
   } catch (final BuildException e) {
       p.fireBuildFinished(e);
   }

   /* exit the current VM */
   System.exit(0);

}

Очень удобно, что тот же самый script используется для начального запуска приложения, а также для перезапуска.

Ответ 9

Окно

public void restartApp(){

    // This launches a new instance of application dirctly, 
    // remember to add some sleep to the start of the cmd file to make sure current instance is
    // completely terminated, otherwise 2 instances of the application can overlap causing strange
    // things:)

    new ProcessBuilder("cmd","/c start /min c:/path/to/script/that/launches/my/application.cmd ^& exit").start();
    System.exit(0);
}

/мин, чтобы запустить script в свернутом окне

^ & выйти в закрытое окно cmd после завершения

образец cmd script может быть

@echo off
rem add some sleep (e.g. 10 seconds) to allow the preceding application instance to release any open resources (like ports) and exit gracefully, otherwise the new instance could fail to start
sleep 10   
set path=C:\someFolder\application_lib\libs;%path%
java -jar application.jar

сон 10 сон в течение 10 секунд

Ответ 10

Просто добавьте информацию, которая отсутствует в других ответах.

Если procfs /proc/self/cmdline доступен

Если вы работаете в среде, которая предоставляет procfs и, следовательно, имеет доступную файловую систему /proc (что означает, что это не портативное решение), вы можете прочитать Java /proc/self/cmdline, чтобы перезапустить его, например:

public static void restart() throws IOException {
    new ProcessBuilder(getMyOwnCmdLine()).inheritIO().start();
}
public static String[] getMyOwnCmdLine() throws IOException {
    return readFirstLine("/proc/self/cmdline").split("\u0000");
}
public static String readFirstLine(final String filename) throws IOException {
    try (final BufferedReader in = new BufferedReader(new FileReader(filename))) {
        return in.readLine();
    }
}

В системах с доступным /proc/self/cmdline это, вероятно, самый элегантный способ "перезапуска" текущего Java-процесса с Java. Ни один JNI не участвовал, и не было никаких предположений о путях и необходимых вещах.

В настоящее время многие системы UNIX, включая GNU/Linux (включая Android), имеют procfs Однако на некоторых, подобных FreeBSD, это устарело и поэтапно вне. Mac OS X является исключением в том смысле, что у нее нет procfs. Windows также не имеет procfs. Cygwin имеет procfs, но он невидим для Java, потому что он виден только приложениям, использующим библиотеки Cygwin вместо системных вызовов Windows, а Java не знает о Cygwin.

Не забудьте использовать ProcessBuilder.inheritIO()

По умолчанию установлено, что stdin/stdout/stderr (в Java под названием System.in/System.out/System.err) начального процесса установлены каналы, которые позволяют текущему запущенному процессу общаться с недавно начатым процессом. Если вы хотите перезапустить текущий процесс, это скорее всего не то, что вы хотите. Вместо этого вы хотели бы, чтобы stdin/stdout/stderr были такими же, как те, которые находятся в текущей виртуальной машине. Это называется унаследованным. Вы можете сделать это, вызвав inheritIO() вашего экземпляра ProcessBuilder.

Pitfall в Windows

Частым вариантом использования функции restart() является перезапуск приложения после обновления. Последний раз, когда я пробовал это в Windows, это было проблематично. При перезаписывании файла приложения .jar с новой версией приложение начало ошибочно вводить и предоставлять исключения в файле .jar. Я просто говорю, если это ваш прецедент. Тогда я решил проблему, обернув приложение в пакетный файл и используя магическое возвращаемое значение из System.exit(), которое я запросил в пакетном файле, и вместо этого пакетный файл перезапустил приложение.

Ответ 11

Старый вопрос и все такое. Но это еще один способ, который дает некоторые преимущества.

В Windows вы можете попросить планировщик задач снова запустить приложение для вас. Преимущество этого заключается в том, что вы ожидаете определенное количество времени до перезапуска приложения. Вы можете перейти к диспетчеру задач и удалить задачу, и она перестает повторяться.

SimpleDateFormat hhmm = new SimpleDateFormat("kk:mm");    
Calendar aCal = Calendar.getInstance(); 
aCal.add(Calendar.SECOND, 65);
String nextMinute = hhmm.format(aCal.getTime()); //Task Scheduler Doesn't accept seconds and won't do current minute.
String[] create = {"c:\\windows\\system32\\schtasks.exe", "/CREATE", "/F", "/TN", "RestartMyProg", "/SC", "ONCE", "/ST", nextMinute, "/TR", "java -jar c:\\my\\dev\\RestartTest.jar"};  
Process proc = Runtime.getRuntime().exec(create, null, null);
System.out.println("Exit Now");
try {Thread.sleep(1000);} catch (Exception e){} // just so you can see it better
System.exit(0);

Ответ 12

Подобно " улучшенному " ответу Yoda, но с дальнейшими улучшениями (как функциональными, читабельными, так и тестируемыми). Теперь он безопасен для запуска и перезапускается столько же раз, сколько задано количество аргументов программы.

  • Отсутствие JAVA_TOOL_OPTIONS.
  • Автоматически находит основной класс.
  • Наследует текущий stdout/stderr.

public static void main(String[] args) throws Exception {
    if (args.length == 0)
        return;
    else
        args = Arrays.copyOf(args, args.length - 1);

    List<String> command = new ArrayList<>(32);
    appendJavaExecutable(command);
    appendVMArgs(command);
    appendClassPath(command);
    appendEntryPoint(command);
    appendArgs(command, args);

    System.out.println(command);
    try {
        new ProcessBuilder(command).inheritIO().start();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

private static void appendJavaExecutable(List<String> cmd) {
    cmd.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
}

private static void appendVMArgs(Collection<String> cmd) {
    Collection<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();

    String javaToolOptions = System.getenv("JAVA_TOOL_OPTIONS");
    if (javaToolOptions != null) {
        Collection<String> javaToolOptionsList = Arrays.asList(javaToolOptions.split(" "));
        vmArguments = new ArrayList<>(vmArguments);
        vmArguments.removeAll(javaToolOptionsList);
    }

    cmd.addAll(vmArguments);
}

private static void appendClassPath(List<String> cmd) {
    cmd.add("-cp");
    cmd.add(ManagementFactory.getRuntimeMXBean().getClassPath());
}

    private static void appendEntryPoint(List<String> cmd) {
    StackTraceElement[] stackTrace          = new Throwable().getStackTrace();
    StackTraceElement   stackTraceElement   = stackTrace[stackTrace.length - 1];
    String              fullyQualifiedClass = stackTraceElement.getClassName();
    String              entryMethod         = stackTraceElement.getMethodName();
    if (!entryMethod.equals("main"))
        throw new AssertionError("Entry point is not a 'main()': " + fullyQualifiedClass + '.' + entryMethod);

    cmd.add(fullyQualifiedClass);
}

private static void appendArgs(List<String> cmd, String[] args) {
    cmd.addAll(Arrays.asList(args));
}

V1.1 Bugfix: нулевой указатель, если JAVA_TOOL_OPTIONS не установлен


Пример:

$ java -cp Temp.jar Temp a b c d e
[/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java, -cp, Temp.jar, Temp, a, b, c, d]
[/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java, -cp, Temp.jar, Temp, a, b, c]
[/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java, -cp, Temp.jar, Temp, a, b]
[/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java, -cp, Temp.jar, Temp, a]
[/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java, -cp, Temp.jar, Temp]
$

Ответ 13

System.err.println("Someone is Restarting me...");
setVisible(false);
try {
    Thread.sleep(600);
} catch (InterruptedException e1) {
    e1.printStackTrace();
}
setVisible(true);

Я думаю, вы действительно не хотите останавливать приложение, но "перезагрузите" его. Для этого вы можете использовать это и добавить свой "Reset" перед сном и после невидимого окна.