Como posso reiniciar um aplicativo Java AWT? Tenho um botão ao qual anexei um manipulador de eventos. Qual código devo usar para reiniciar o aplicativo?
Quero fazer a mesma coisa que Application.Restart()
faço em um aplicativo C #.
Como posso reiniciar um aplicativo Java AWT? Tenho um botão ao qual anexei um manipulador de eventos. Qual código devo usar para reiniciar o aplicativo?
Quero fazer a mesma coisa que Application.Restart()
faço em um aplicativo C #.
Respostas:
Claro, é possível reiniciar um aplicativo Java.
O método a seguir mostra uma maneira de reiniciar um aplicativo 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);
}
Basicamente, ele faz o seguinte:
MyClassInTheJar
classe para encontrar o próprio local do jar)System.exit(0)
termina o processo filho tem a mesma resposta que se essa resposta realmente funciona e por quê. Se você não puder fornecer uma explicação sensata junto com sua resposta, você fez um péssimo trabalho. Uma resposta que fornece mais perguntas do que respostas não é um exemplo de resposta completa. Boas respostas não apenas mostram o código, mas também explicam como e por que funcionam, quais são as desvantagens e quais são as alternativas. Você nem tentou cobrir essas coisas.
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);
}
}
Dedicado a todos aqueles que dizem que é impossível.
Este programa coleta todas as informações disponíveis para reconstruir a linha de comando original. Em seguida, ele o inicia e, como é o mesmo comando, seu aplicativo inicia uma segunda vez. Então, saímos do programa original, o programa filho continua em execução (mesmo no Linux) e faz exatamente a mesma coisa.
AVISO : Se você executar isso, lembre-se de que nunca termina criando novos processos, semelhante a uma bomba fork .
ManagementFactory.getRuntimeMXBean().getInputArguments()
fornecerá apenas os argumentos de entrada passados para a JVM. Ele perde parâmetros passados para seu aplicativo. por exemplo, java -jar start.jar -MISSED_PARAM=true
. Em um oracle jvm, você pode recuperar esses parâmetros usando System.getProperty("sun.java.command")
.
ProcessBuilder
e inheritIO()
, a VM filha pode ser iniciada de forma que a VM pai seja encerrada.
Basicamente, você não pode. Pelo menos não de maneira confiável. No entanto, você não deve precisar.
Para reiniciar um programa Java, você precisa reiniciar o JVM. Para reiniciar o JVM você precisa
Localize o java
lançador que foi usado. Você pode tentar, System.getProperty("java.home")
mas não há garantia de que isso realmente apontará para o inicializador que foi usado para iniciar seu aplicativo. (O valor retornado pode não apontar para o JRE usado para iniciar o aplicativo ou pode ter sido substituído por -Djava.home
.)
Você presumivelmente quer honrar a memória original configurações etc ( -Xmx
, -Xms
...) então você precisa descobrir quais configurações onde usado para iniciar a primeira JVM. Você pode tentar usar, ManagementFactory.getRuntimeMXBean().getInputArguments()
mas não há garantia de que isso refletirá as configurações usadas. Isso está até mesmo explicitado na documentação desse método:
Normalmente, nem todas as opções de linha de comando para o comando 'java' são passadas para a máquina virtual Java. Portanto, os argumentos de entrada retornados podem não incluir todas as opções de linha de comando.
Se o seu programa lê a entrada do Standard.in
stdin original, ele será perdido na reinicialização.
Muitos desses truques e hacks falharão na presença de um SecurityManager
.
Eu recomendo que você projete seu aplicativo de forma que seja fácil limpar tudo e depois crie uma nova instância de sua classe "principal".
Muitos aplicativos são projetados para fazer nada além de criar uma instância no método principal:
public class MainClass {
...
public static void main(String[] args) {
new MainClass().launch();
}
...
}
Usando esse padrão, deve ser fácil fazer algo como:
public class MainClass {
...
public static void main(String[] args) {
boolean restart;
do {
restart = new MainClass().launch();
} while (restart);
}
...
}
e deixe launch()
retornar verdadeiro se e somente se o aplicativo foi encerrado de uma forma que precisa ser reiniciado.
Estritamente falando, um programa Java não pode reiniciar a si mesmo, pois para isso ele deve matar a JVM na qual está sendo executado e reiniciá-la, mas uma vez que a JVM não está mais em execução (morta), nenhuma ação pode ser realizada.
Você poderia fazer alguns truques com carregadores de classe personalizados para carregar, empacotar e iniciar os componentes AWT novamente, mas isso provavelmente causará muitas dores de cabeça em relação ao loop de eventos da GUI.
Dependendo de como o aplicativo é iniciado, você pode iniciar a JVM em um script de wrapper que contém um loop do / while, que continua enquanto a JVM sai com um código específico, então o aplicativo AWT teria que chamar System.exit(RESTART_CODE)
. Por exemplo, em pseudocódigo de script:
DO
# Launch the awt program
EXIT_CODE = # Get the exit code of the last process
WHILE (EXIT_CODE == RESTART_CODE)
O aplicativo AWT deve sair da JVM com algo diferente de RESTART_CODE na terminação "normal" que não requer reinicialização.
JavaApplicationStub
... Não tenho certeza se existe uma maneira fácil de contornar isso.
O Eclipse normalmente reinicia após a instalação de um plug-in. Eles fazem isso usando um wrapper eclipse.exe (aplicativo inicializador) para janelas. Este aplicativo executa o jar do executor eclipse principal e se o aplicativo eclipse java terminar com um código de reinicialização, eclipse.exe reinicia o ambiente de trabalho. Você pode construir um bit semelhante de código nativo, script de shell ou outro wrapper de código Java para conseguir a reinicialização.
janelas
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 para iniciar o script na janela minimizada
^ & saia para fechar a janela cmd após terminar
um script cmd de amostra pode ser
@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
dormir 10 dormir por 10 segundos
Se você realmente precisa reiniciar seu aplicativo, pode escrever um aplicativo separado para iniciá-lo ...
Esta página fornece muitos exemplos diferentes para cenários diferentes:
Embora essa pergunta seja antiga e respondida, me deparei com um problema com algumas das soluções e decidi adicionar minha sugestão à mistura.
O problema com algumas das soluções é que elas criam uma única string de comando. Isso cria problemas quando alguns parâmetros contêm espaços, especialmente java.home .
Por exemplo, no Windows, a linha
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
Pode retornar algo assim:C:\Program Files\Java\jre7\bin\java
Esta string deve ser colocada entre aspas ou escapada devido ao espaço em Program Files
. Não é um grande problema, mas um tanto chato e sujeito a erros, especialmente em aplicativos de plataforma cruzada.
Portanto, minha solução cria o comando como uma matriz de comandos:
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();
}
}
Eu mesmo estava pesquisando o assunto quando me deparei com essa pergunta.
Apesar do fato de que a resposta já foi aceita, eu ainda gostaria de oferecer uma abordagem alternativa para completude. Especificamente, o Apache Ant serviu como uma solução muito flexível.
Basicamente, tudo se resume a um arquivo de script Ant com uma única tarefa de execução Java (consulte aqui e aqui ) invocada a partir de um código Java (consulte aqui ). Este código Java, que pode ser um lançamento de método , pode ser uma parte do aplicativo que precisa ser reiniciado. O aplicativo precisa ter uma dependência da biblioteca Apache Ant (jar).
Sempre que o aplicativo precisa ser reiniciado, ele deve chamar o lançamento do método e sair da VM. A tarefa Ant java deve ter as opções fork e spawn definidas como true.
Aqui está um exemplo de um 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>
O código para o método de inicialização pode ser parecido com este:
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);
}
Uma coisa muito conveniente aqui é que o mesmo script é usado para a inicialização do aplicativo inicial, bem como para reinicializações.
Apenas adicionando informações que não estão presentes em outras respostas.
/proc/self/cmdline
estiver disponívelSe você estiver executando em um ambiente que fornece procfs e, portanto, tem o /proc
sistema de arquivos disponível (o que significa que esta não é uma solução portátil), você pode fazer a leitura do Java /proc/self/cmdline
para reiniciar a si mesmo, assim:
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();
}
}
Em sistemas com /proc/self/cmdline
disponível, esta provavelmente é a maneira mais elegante de como "reiniciar" o processo Java atual do Java. Nenhum JNI envolvido e nenhuma suposição de caminhos e outras coisas necessárias. Isso também cuidará de todas as opções JVM passadas para o java
binário. A linha de comando será exatamente idêntica àquela do processo JVM atual.
Muitos sistemas UNIX incluindo GNU / Linux (incluindo Android) hoje em dia têm procfs. No entanto, em alguns como o FreeBSD, ele está obsoleto e está sendo descontinuado. O Mac OS X é uma exceção no sentido de que não possui procfs . O Windows também não tem procfs . O Cygwin tem procfs, mas é invisível para Java porque só é visível para aplicativos que usam DLLs do Cygwin em vez de chamadas de sistema do Windows, e o Java não conhece o Cygwin.
ProcessBuilder.inheritIO()
O padrão é que stdin
/ stdout
/ stderr
(em Java chamado System.in
/ System.out
/ System.err
) do processo iniciado seja definido como canais que permitem que o processo atualmente em execução se comunique com o processo recém-iniciado. Se você deseja reiniciar o processo atual, provavelmente não é isso que você deseja . Em vez disso, você deseja que stdin
/ stdout
/ stderr
sejam iguais aos da VM atual. Isso é chamado de herdado . Você pode fazer isso chamando inheritIO()
sua ProcessBuilder
instância.
Um caso de uso frequente de uma restart()
função é reiniciar o aplicativo após uma atualização. A última vez que tentei isso no Windows, isso foi problemático. Ao sobrescrever o .jar
arquivo do aplicativo com a nova versão, o aplicativo passou a apresentar mau funcionamento e .jar
abrir exceções sobre o arquivo. Estou apenas dizendo, caso este seja o seu caso de uso. Naquela época, resolvi o problema envolvendo o aplicativo em um arquivo em lote e usando um valor de retorno mágico System.exit()
daquele que consultei no arquivo em lote e fiz com que o arquivo em lote reiniciasse o aplicativo.
Pergunta antiga e tudo isso. Mas esta é mais uma forma que oferece algumas vantagens.
No Windows, você pode pedir ao agendador de tarefas para iniciar seu aplicativo novamente para você. Isso tem a vantagem de esperar um determinado período de tempo antes que o aplicativo seja reiniciado. Você pode ir para o gerenciador de tarefas e excluir a tarefa e ela para de se repetir.
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);
Semelhante à resposta ' melhorada ' de Yoda , mas com outras melhorias (tanto funcional, legibilidade e testabilidade). Agora é seguro executar e reiniciar tantas vezes quanto a quantidade de argumentos de programa fornecidos.
JAVA_TOOL_OPTIONS
opções.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: ponteiro nulo se JAVA_TOOL_OPTIONS não estiver definido
Exemplo:
$ 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]
$
System.err.println("Someone is Restarting me...");
setVisible(false);
try {
Thread.sleep(600);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
setVisible(true);
Eu acho que você realmente não quer parar o aplicativo, mas sim "Reiniciá-lo". Para isso, você pode usar isso e adicionar o seu "Reset" antes de dormir e depois da janela invisível.