Azf*_*iaz 92 java restart application-restart
如何重新启动Java AWT应用程序?我有一个按钮,我附加了一个事件处理程序.我应该使用什么代码来重启应用程序?
我想做与Application.Restart()C#应用程序相同的事情.
Veg*_*ger 103
当然可以重新启动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);
}
Run Code Online (Sandbox Code Playgroud)
基本上它执行以下操作:
MyClassInTheJar类来查找jar位置本身的jar)Mei*_*bur 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);
}
}
Run Code Online (Sandbox Code Playgroud)
致力于所有那些说不可能的人.
该程序收集可用于重建原始命令行的所有信息.然后,它启动它,因为它是完全相同的命令,您的应用程序第二次启动.然后我们退出原始程序,子程序仍在运行(即使在Linux下)也做同样的事情.
警告:如果你运行它,请注意它永远不会结束创建新进程,类似于fork炸弹.
aio*_*obe 22
基本上,你不能.至少不是以可靠的方式.
要重新启动Java程序,需要重新启动JVM.要重新启动JVM
找到使用的java启动器.你可以试试,System.getProperty("java.home")但不能保证这实际上会指向用于启动你的应用程序的启动器.(返回的值可能不会指向用于启动应用程序的JRE,或者它可能已被覆盖-Djava.home.)
您可能希望尊重原始内存设置等(-Xmx,-Xms...),因此您需要确定用于启动第一个JVM的设置.您可以尝试使用,ManagementFactory.getRuntimeMXBean().getInputArguments()但不能保证这将反映使用的设置.这甚至在该方法的文档中详细说明:
通常,并非'java'命令的所有命令行选项都传递给Java虚拟机.因此,返回的输入参数可能不包括所有命令行选项.
如果您的程序从Standard.in原始stdin 读取输入将在重新启动时丢失.
很多这些技巧和黑客都会在存在的情况下失败SecurityManager.
另一方面:你不应该这样做.
我建议你设计你的应用程序,这样就可以很容易地清理每一个东西,然后创建一个新的"main"类实例.
许多应用程序只是在main方法中创建一个实例而不做任何事情:
public class MainClass {
...
public static void main(String[] args) {
new MainClass().launch();
}
...
}
Run Code Online (Sandbox Code Playgroud)
通过使用这种模式,它应该很容易做类似的事情:
public class MainClass {
...
public static void main(String[] args) {
boolean restart;
do {
restart = new MainClass().launch();
} while (restart);
}
...
}
Run Code Online (Sandbox Code Playgroud)
让launch()当且仅它需要重新启动如果应用程序的方式关闭返回true.
严格来说,Java程序无法自行重启,因为它必须杀死运行它的JVM然后再次启动它,但是一旦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)
Run Code Online (Sandbox Code Playgroud)
AWT应用程序应该在"正常"终止时使用RESTART_CODE之外的其他东西退出JVM,这不需要重新启动.
Eclipse通常在安装插件后重新启动.他们使用包装器eclipse.exe(启动器应用程序)为Windows执行此操作.这个应用程序执行核心eclipse运行程序jar,如果eclipse java应用程序以重新启动代码终止,eclipse.exe将重新启动工作台.您可以构建类似的本机代码,shell脚本或其他Java代码包装器来实现重启.
视窗
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);
}
Run Code Online (Sandbox Code Playgroud)
/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
Run Code Online (Sandbox Code Playgroud)
sleep 10 sleep 10 秒
虽然这个问题很老而且已经回答了,但我偶然发现了一些解决方案的问题,并决定将我的建议添加到组合中。
一些解决方案的问题在于它们构建了单个命令字符串。当某些参数包含空格时,这会产生问题,尤其是java.home。
例如,在 Windows 上,该行
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
Run Code Online (Sandbox Code Playgroud)
可能会返回这样的东西: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();
}
}
Run Code Online (Sandbox Code Playgroud)
只是添加其他答案中不存在的信息。
/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();
}
}
Run Code Online (Sandbox Code Playgroud)
在/proc/self/cmdline可用的系统上,这可能是如何从 Java“重新启动”当前 Java 进程的最优雅的方式。不涉及 JNI,也不需要猜测路径和所需的东西。这还将处理传递给java二进制文件的所有 JVM 选项。命令行将与当前 JVM 进程之一完全相同。
现在包括 GNU/Linux(包括 Android)在内的许多 UNIX 系统都有procfs但是在一些像 FreeBSD 上,它已被弃用并被逐步淘汰。Mac OS X是一个例外,因为它没有 procfs。Windows也没有procfs。Cygwin 有procfs但它对 Java 不可见,因为它只对使用 Cygwin DLL 而不是 Windows 系统调用的应用程序可见,而且 Java 不知道 Cygwin。
ProcessBuilder.inheritIO()缺省值是stdin/ stdout/ stderr(在Java中称为System.in/ System.out/ System.err)启动的过程被设置为管,其允许当前运行的进程与新启动的过程进行通信。如果您想重新启动当前进程,这很可能不是您想要的。相反,你想的是stdin/ stdout/stderr是相同当前VM的。这称为继承。您可以通过调用inheritIO()您的ProcessBuilder实例来实现。
restart()函数的一个常见用例是在更新后重新启动应用程序。上次我在 Windows 上尝试这个是有问题的。当.jar用新版本覆盖应用程序的文件时,应用程序开始行为不端并给出有关.jar文件的异常。我只是告诉,如果这是您的用例。当时我通过将应用程序包装在批处理文件中并使用System.exit()我在批处理文件中查询的魔术返回值解决了这个问题,并让批处理文件重新启动应用程序。
| 归档时间: |
|
| 查看次数: |
162066 次 |
| 最近记录: |