104

Java AWT アプリケーションを再起動するにはどうすればよいですか? イベント ハンドラーをアタッチしたボタンがあります。アプリケーションを再起動するには、どのコードを使用すればよいですか?

Application.Restart()C# アプリケーションと同じことをしたい。

4

13 に答える 13

112

もちろん、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);
}

基本的には、次のことを行います。

  1. Java 実行可能ファイルを見つけます (ここでは Java バイナリを使用しましたが、要件によって異なります)。
  2. アプリケーションを見つけます(私の場合はjarで、MyClassInTheJarクラスを使用してjarの場所自体を見つけます)
  3. jar を再起動するコマンドを作成します (この場合は Java バイナリを使用)
  4. 実行してください!(したがって、現在のアプリケーションを終了し、再度開始します)
于 2010-11-16T12:42:56.577 に答える
35
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);
    }
}

それは不可能だと言うすべての人に捧げます。

このプログラムは、元のコマンドラインを再構築するために利用可能なすべての情報を収集します。次に、それを起動します。これはまったく同じコマンドであるため、アプリケーションは2回目に起動します。次に、元のプログラムを終了します。子プログラムは(Linuxでも)実行されたままで、まったく同じことを行います。

警告:これを実行する場合は、フォーク爆弾のように、新しいプロセスの作成が終了しないことに注意してください。

于 2010-11-12T00:19:11.723 に答える
32

基本的に、できません。少なくとも信頼できる方法ではありません。ただし、その必要はありません。

別れられない

Java プログラムを再起動するには、JVM を再起動する必要があります。JVMを再起動するには、次のことが必要です

  1. java使用されたランチャーを見つけます。試してみることはできますがSystem.getProperty("java.home")、これがアプリケーションの起動に使用されたランチャーを実際に指すという保証はありません。(返された値は、アプリケーションの起動に使用された JRE を指していないか、によってオーバーライドされた可能性があります-Djava.home。)

  2. -Xmxおそらく、元のメモリ設定など ( 、 、…)を尊重したい-Xmsので、最初の JVM の起動に使用された設定を把握する必要があります。使用してみることができますがManagementFactory.getRuntimeMXBean().getInputArguments()、これが使用した設定を反映するという保証はありません。これは、そのメソッドのドキュメントでも詳しく説明されています。

    通常、「java」コマンドのすべてのコマンドライン オプションが Java 仮想マシンに渡されるわけではありません。したがって、返される入力引数には、すべてのコマンドライン オプションが含まれていない場合があります。

  3. Standard.inプログラムが元の標準入力から入力を読み取る場合、再起動時に失われます。

  4. これらのトリックやハックの多くは、SecurityManager.

いらない部分

すべてのものを簡単にクリーンアップできるようにアプリケーションを設計し、その後「メイン」クラスの新しいインスタンスを作成することをお勧めします。

多くのアプリケーションは、main メソッドでインスタンスを作成するだけで何もしないように設計されています。

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 を返します。

于 2010-11-11T22:20:24.900 に答える
14

厳密に言えば、Java プログラムは実行中の JVM を強制終了してから再起動する必要があるため、それ自体を再起動することはできません。

カスタム クラスローダーを使用して、AWT コンポーネントを再度ロード、パック、および開始するためのいくつかのトリックを実行できますが、これにより、GUI イベント ループに関して多くの頭痛の種が発生する可能性があります。

アプリケーションの起動方法によっては、do/while ループを含むラッパー スクリプトで JVM を起動できます。このループは、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 アプリは、再起動を必要としない「通常の」終了時に RESTART_CODE 以外の何かで JVM を終了する必要があります。

于 2010-11-11T22:23:06.610 に答える
7

Eclipseは通常、プラグインがインストールされた後に再起動します。これは、Windows用のラッパーeclipse.exe(ランチャーアプリ)を使用して行います。このアプリケーションは、コアのeclipse runner jarを実行し、eclipse javaアプリケーションが再起動コードで終了した場合、eclipse.exeはワークベンチを再起動します。同様のネイティブコード、シェルスクリプト、または別のJavaコードラッパーを作成して、再起動を実現できます。

于 2010-11-11T22:29:01.947 に答える
6

ウィンドウズ

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

/min最小化されたウィンドウでスクリプトを開始する

^&終了後、終了してcmdウィンドウを閉じます

サンプルの cmd スクリプトは次のようになります。

@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 秒間睡眠

于 2014-10-01T13:35:32.607 に答える
5

この質問は古くて答えがありますが、いくつかの解決策で問題に遭遇し、私の提案をミックスに追加することにしました.

一部のソリューションの問題は、単一のコマンド文字列を作成することです。これにより、一部のパラメータ、特にjava.homeにスペースが含まれている場合に問題が発生します。

たとえば、Windows では、次の行

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();
        }
    }
于 2015-01-11T12:24:34.903 に答える
4

本当にアプリを再起動する必要がある場合は、別のアプリを作成して起動することができます...

このページでは、さまざまなシナリオのさまざまな例を示します。

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

于 2010-11-11T22:19:18.680 に答える
4

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 バグ修正: JAVA_TOOL_OPTIONS が設定されていない場合の null ポインター


例:

$ 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]
$
于 2018-02-26T16:28:11.087 に答える
3

この質問に出くわしたとき、私は自分で主題を研究していました。

答えがすでに受け入れられているという事実に関係なく、完全を期すために別のアプローチを提供したいと思います。特に、Apache Ant は非常に柔軟なソリューションとして機能しました。

基本的に、すべてはJava コード (ここを参照) から呼び出される単一の Java 実行タスク (ここここを参照) を持つ Ant スクリプト ファイルに要約されます。メソッドlaunchである可能性があるこの Java コードは、再起動が必要なアプリケーションの一部である可能性があります。アプリケーションは、Apache Ant ライブラリ (jar) に依存する必要があります。

アプリケーションを再起動する必要があるときはいつでも、メソッドの起動を呼び出して VM を終了する必要があります。Ant java タスクでは、オプションforkspawnを true に設定する必要があります。

Ant スクリプトの例を次に示します。

<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>

launchメソッドのコードは次のようになります。

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

}

ここで非常に便利なのは、最初のアプリケーションの起動と再起動に同じスクリプトが使用されることです。

于 2010-12-12T20:09:59.463 に答える
2

古い質問とそのすべて。しかし、これはいくつかの利点を提供するもう 1 つの方法です。

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);
于 2016-05-16T03:44:21.790 に答える
-14
System.err.println("Someone is Restarting me...");
setVisible(false);
try {
    Thread.sleep(600);
} catch (InterruptedException e1) {
    e1.printStackTrace();
}
setVisible(true);

アプリケーションを本当に停止したいのではなく、「再起動」したいと思います。そのために、これを使用して、スリープの前と目に見えないウィンドウの後に「リセット」を追加できます。

于 2013-11-03T19:17:20.947 に答える