如何重新启动 Java 应用程序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4159802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I restart a Java application?
提问by Azfar Niaz
How can I restart a Java AWT application? I have a button to which I have attached an event handler. What code should I use to restart the application?
如何重新启动 Java AWT 应用程序?我有一个按钮,我附加了一个事件处理程序。我应该使用什么代码来重新启动应用程序?
I want to do the same thing that Application.Restart()
do in a C# application.
我想做与Application.Restart()
在 C# 应用程序中所做的相同的事情。
采纳答案by Veger
Of course it is possible to restart a Java application.
当然,可以重新启动 Java 应用程序。
The following method shows a way to restart a Java 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);
}
Basically it does the following:
基本上它执行以下操作:
- Find the java executable (I used the java binary here, but that depends on your requirements)
- Find the application (a jar in my case, using the
MyClassInTheJar
class to find the jar location itself) - Build a command to restart the jar (using the java binary in this case)
- Execute it! (and thus terminating the current application and starting it again)
- 找到 java 可执行文件(我在这里使用了 java 二进制文件,但这取决于您的要求)
- 找到应用程序(在我的例子中是一个 jar,使用
MyClassInTheJar
类来查找 jar 位置本身) - 构建一个命令来重新启动 jar(在这种情况下使用 java 二进制文件)
- 执行它!(从而终止当前应用程序并重新启动它)
回答by Sean W.
If you realy need to restart your app, you could write a separate app the start it...
如果你真的需要重新启动你的应用程序,你可以编写一个单独的应用程序来启动它......
This page provides many different examples for different scenarios:
此页面针对不同的场景提供了许多不同的示例:
回答by aioobe
Basically, you can't. At least not in a reliable way. However, you shouldn't need to.
基本上,你不能。至少不是以可靠的方式。但是,您应该不需要。
The can'tpart
在不能部分
To restart a Java program, you need to restart the JVM. To restart the JVM you need to
要重新启动 Java 程序,您需要重新启动 JVM。要重新启动 JVM,您需要
Locate the
java
launcher that was used. You may try withSystem.getProperty("java.home")
but there's no guarantee that this will actually point to the launcher that was used to launch your application. (The value returned may not point to the JRE used to launch the applicationor it could have been overridden by-Djava.home
.)You would presumably want to honor the original memory settings etc (
-Xmx
,-Xms
, …) so you need to figure out which settings where used to start the first JVM. You could try usingManagementFactory.getRuntimeMXBean().getInputArguments()
but there's no guarantee that this will reflect the settings used. This is even spelled out in the documentationof that method:Typically, not all command-line options to the 'java' command are passed to the Java virtual machine. Thus, the returned input arguments may not include all command-line options.
If your program reads input from
Standard.in
the original stdin will be lost in the restart.Lots of these tricks and hacks will fail in the presence of a
SecurityManager
.
找到使用的
java
启动器。您可以尝试使用,System.getProperty("java.home")
但不能保证这实际上会指向用于启动您的应用程序的启动器。(返回的值可能不指向用于启动应用程序的 JRE,或者它可能已被 覆盖-Djava.home
。)您可能希望遵守原始内存设置等(
-Xmx
、、-Xms
……),因此您需要确定用于启动第一个 JVM 的设置。您可以尝试使用,ManagementFactory.getRuntimeMXBean().getInputArguments()
但不能保证这将反映所使用的设置。这甚至在该方法的文档中都有说明:通常,并非“java”命令的所有命令行选项都会传递给 Java 虚拟机。因此,返回的输入参数可能不包括所有命令行选项。
如果你的程序从
Standard.in
原来的 stdin读取输入将在重启时丢失。许多这些技巧和技巧在
SecurityManager
.
The shouldn't needpart
本不应该需要部分
I recommend you to design your application so that it is easy to clean every thing up and after that create a new instance of your "main" class.
我建议您设计您的应用程序,以便轻松清理所有内容,然后创建“主”类的新实例。
Many applications are designed to do nothing but create an instance in the main-method:
许多应用程序被设计为除了在 main-method 中创建一个实例之外什么都不做:
public class MainClass {
...
public static void main(String[] args) {
new MainClass().launch();
}
...
}
By using this pattern, it should be easy enough to do something like:
通过使用这种模式,它应该很容易做如下事情:
public class MainClass {
...
public static void main(String[] args) {
boolean restart;
do {
restart = new MainClass().launch();
} while (restart);
}
...
}
and let launch()
return true if and only if the application was shut down in a way that it needs to be restarted.
并且launch()
当且仅当应用程序以需要重新启动的方式关闭时才返回 true。
回答by maerics
Strictly speaking, a Java program cannot restart itself since to do so it must kill the JVM in which it is running and then start it again, but once the JVM is no longer running (killed) then no action can be taken.
严格来说,Java 程序无法自行重启,因为这样做必须终止运行它的 JVM,然后再次启动它,但是一旦 JVM 不再运行(终止),则无法采取任何措施。
You could do some tricks with custom classloaders to load, pack, and start the AWT components again but this will likely cause lots of headaches with regard to the GUI event loop.
您可以使用自定义类加载器做一些技巧来再次加载、打包和启动 AWT 组件,但这可能会导致很多关于 GUI 事件循环的麻烦。
Depending on how the application is launched, you could start the JVM in a wrapper script which contains a do/while loop, which continues while the JVM exits with a particular code, then the AWT app would have to call System.exit(RESTART_CODE)
. For example, in scripting pseudocode:
根据应用程序的启动方式,您可以在包含 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)
The AWT app should exit the JVM with something other than the RESTART_CODE on "normal" termination which doesn't require restart.
AWT 应用程序应该在不需要重新启动的“正常”终止时使用 RESTART_CODE 以外的其他内容退出 JVM。
回答by whatnick
Eclipse typically restarts after a plugin is installed. They do this using a wrapper eclipse.exe (launcher app) for windows. This application execs the core eclipse runner jar and if the eclipse java application terminates with a relaunch code, eclipse.exe restarts the workbench. You can build a similar bit of native code, shell script or another java code wrapper to achieve the restart.
Eclipse 通常会在安装插件后重新启动。他们使用 Windows 的包装器 eclipse.exe(启动器应用程序)来执行此操作。此应用程序执行核心 eclipse runner jar,如果 eclipse java 应用程序以重新启动代码终止,则 eclipse.exe 将重新启动工作台。您可以构建一些类似的本机代码、shell 脚本或其他 java 代码包装器来实现重新启动。
回答by Meinersbur
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);
}
}
Dedicated to all those who say it is impossible.
献给所有那些说不可能的人。
This program collects all information available to reconstruct the original commandline. Then, it launches it and since it is the very same command, your application starts a second time. Then we exit the original program, the child program remains running (even under Linux) and does the very same thing.
该程序收集所有可用于重建原始命令行的信息。然后,它启动它,因为它是完全相同的命令,您的应用程序第二次启动。然后我们退出原始程序,子程序保持运行(即使在 Linux 下)并做同样的事情。
WARNING: If you run this, be aware that it never ends creating new processes, similar to a fork bomb.
警告:如果您运行它,请注意它永远不会结束创建新进程,类似于fork 炸弹。
回答by 01es
I was researching the subject myself when came across this question.
遇到这个问题时,我自己正在研究这个主题。
Regardless of the fact that the answer is already accepted, I would still like to offer an alternative approach for completeness. Specifically, Apache Ant served as a very flexible solution.
不管答案已经被接受,我仍然想提供一种替代方法来实现完整性。具体来说,Apache Ant 是一个非常灵活的解决方案。
Basically, everything boils down to an Ant script file with a single Java execution task (refer hereand here) invoked from a Java code (see here). This Java code, which can be a method launch, could be a part of the application that needs to be restarted. The application needs to have a dependency on the Apache Ant library (jar).
基本上,一切都归结为一个单一的Java执行任务的Ant脚本文件(参见这里和这里)从Java代码中调用(参见这里)。此 Java 代码可以是方法launch,也可以是需要重新启动的应用程序的一部分。应用程序需要依赖于 Apache Ant 库 (jar)。
Whenever application needs to be restarted, it should call method launchand exit the VM. The Ant java task should have options forkand spawnset to true.
每当应用程序需要重新启动时,它应该调用方法启动并退出虚拟机。Ant java 任务应该将选项fork和spawn设置为 true。
Here is an example of an Ant script:
下面是一个 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>
The code for the launchmethod may look something like this:
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);
}
}
A very convenient thing here is that the same script is used for initial application start up as well as for restarts.
这里非常方便的是,相同的脚本用于初始应用程序启动和重新启动。
回答by NBStudios
System.err.println("Someone is Restarting me...");
setVisible(false);
try {
Thread.sleep(600);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
setVisible(true);
I guess you don't really want to stop the application, but to "Restart" it. For that, you could use this and add your "Reset" before the sleep and after the invisible window.
我猜您并不是真的想停止应用程序,而是要“重新启动”它。为此,您可以使用它并在睡眠之前和隐形窗口之后添加“重置”。
回答by Amr Lotfy
Windows
视窗
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);
}
/minto start script in minimized window
/min在最小化窗口中启动脚本
^&exit to close cmd window after finish
^&完成后退出以关闭 cmd 窗口
a sample cmd script could be
一个示例 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
sleep 10sleep for 10 seconds
sleep 10sleep 10 秒
回答by Malt
Although this question is old and answered, I've stumbled across a problem with some of the solutions and decided to add my suggestion into the mix.
虽然这个问题很老而且已经回答了,但我偶然发现了一些解决方案的问题,并决定将我的建议添加到组合中。
The problem with some of the solutions is that they build a single command string. This creates issues when some parameters contain spaces, especially java.home.
一些解决方案的问题在于它们构建了单个命令字符串。当某些参数包含空格时,这会产生问题,尤其是java.home。
For example, on windows, the line
例如,在 Windows 上,该行
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
Might return something like this:C:\Program Files\Java\jre7\bin\java
可能会返回这样的东西:C:\Program Files\Java\jre7\bin\java
This string has to be wrapped in quotes or escaped due to the space in Program Files
. Not a huge problem, but somewhat annoying and error prone, especially in cross platform applications.
由于Program Files
. 不是一个大问题,但有点烦人且容易出错,尤其是在跨平台应用程序中。
Therefore my solution builds the command as an arrayof commands:
因此,我的解决方案将命令构建为命令数组:
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();
}
}