varios proyecto programa iniciar ejecutar desde consola compilar como comandos comando java process exec

proyecto - Ejecutar una aplicación Java en un proceso separado



java cmd (9)

¿Se puede cargar una aplicación Java en un proceso separado utilizando su nombre, en lugar de su ubicación, de manera independiente de la plataforma?

Sé que puedes ejecutar un programa a través de ...

Process process = Runtime.getRuntime().exec( COMMAND );

... el problema principal de este método es que dichas llamadas son específicas de la plataforma.


Idealmente, envolvería un método en algo tan simple como ...

EXECUTE.application( CLASS_TO_BE_EXECUTED );

... y pasar el nombre completo de una clase de aplicación como CLASS_TO_BE_EXECUTED .


¿Realmente tienes que lanzarlos de forma nativa? ¿Podrías llamar directamente a sus métodos "principales"? Lo único especial de main es que el iniciador de VM lo llama, nada le impide llamar a main usted mismo.



Ampliando la respuesta de @ stepancheg, el código real se vería así (en forma de una prueba).

import org.junit.Test; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.stream.Collectors; public class SpinningUpAJvmTest { @Test public void shouldRunAJvm() throws Exception { String classpath = Arrays.stream(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs()) .map(URL::getFile) .collect(Collectors.joining(File.pathSeparator)); Process process = new ProcessBuilder( System.getProperty("java.home") + "/bin/java", "-classpath", classpath, MyMainClass.class.getCanonicalName() // main class arguments go here ) .inheritIO() .start(); int exitCode = process.waitFor(); System.out.println("process stopped with exitCode " + exitCode); } }


Dos consejos:

System.getProperty("java.home") + "/bin/java" le da una ruta al ejecutable java.

((URLClassLoader() Thread.currentThread().getContextClassLoader()).getURL() ayuda a reconstruir el classpath de la aplicación actual.

Entonces su aplicación EXECUTE.application es justa (pseudocódigo):

Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)


Esta es una síntesis de algunas de las otras respuestas que se han proporcionado. Las propiedades del sistema Java proporcionan suficiente información para llegar a la ruta al comando java y al classpath en lo que, creo, es una plataforma independiente.

public final class JavaProcess { private JavaProcess() {} public static int exec(Class klass) throws IOException, InterruptedException { String javaHome = System.getProperty("java.home"); String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; String classpath = System.getProperty("java.class.path"); String className = klass.getCanonicalName(); ProcessBuilder builder = new ProcessBuilder( javaBin, "-cp", classpath, className); Process process = builder.start(); process.waitFor(); return process.exitValue(); } }

Ejecutaría este método así:

int status = JavaProcess.exec(MyClass.class);

Pensé que tenía sentido pasar la clase real en lugar de la representación de cadena del nombre, ya que la clase tiene que estar en la ruta de clase de todos modos para que esto funcione.


Esto podría ser un exceso para usted, pero Project Akuma hace lo que quiere y más. Lo encontré a través de esta entrada en el blog fabulosamente útil de Kohsuke (uno de los programadores de inicio de rock de Sun).


Siguiendo con lo que TofuBeer dijo: ¿Estás seguro de que realmente necesitas desviar otra JVM? La JVM tiene un buen soporte para la concurrencia en estos días, por lo que puede obtener una gran cantidad de funcionalidades relativamente baratas simplemente girando uno o dos subprocesos nuevos (que pueden o no requerir llamadas a Foo # main (String [])). Consulte java.util.concurrent para obtener más información.

Si decide bifurcar, se prepara para un poco de complejidad relacionada con la búsqueda de recursos necesarios. Es decir, si su aplicación cambia con frecuencia y depende de un grupo de archivos jar, tendrá que hacer un seguimiento de todos ellos para que puedan pasarse a classpath arg. Además, tal enfoque requiere inferir tanto la ubicación de la JVM (actualmente en ejecución) (que puede no ser precisa) como la ubicación de la ruta de clases actual (que es aún menos probable que sea precisa, dependiendo de la forma en que se genere el desove El subproceso se ha invocado: jar, jnlp, explosion .classes dir, algún contenedor, etc.).

Por otro lado, la vinculación a los métodos estáticos #main tiene sus dificultades también. Los modificadores estáticos tienen una desagradable tendencia a filtrarse a otro código y generalmente son mal vistos por personas con mentalidad de diseño.


Un problema que ocurre cuando ejecuta esto desde una GUI java es que se ejecuta en segundo plano. Por lo tanto, no puede ver el símbolo del sistema en absoluto.

Para evitar esto, debe ejecutar java.exe a través de "cmd.exe" Y "iniciar". No sé por qué, pero si pones "cmd / c start" delante, muestra el símbolo del sistema mientras se ejecuta.

Sin embargo, el problema con "inicio" es que hay un espacio en la ruta de acceso a la aplicación (que la ruta al exe java generalmente tiene como está en C: / Archivos de programa / Java / jre6 / bin / java.exe o similar), luego el inicio simplemente falla con "no se puede encontrar c: / Program"

Por lo tanto, debe colocar comillas en C: / Archivos de programa / Java / jre6 / bin / java.exe. Ahora, el inicio se queja de los parámetros que pasa a java.exe: "El sistema no puede encontrar el archivo -cp".

Escapar el espacio en "Archivos de programa" con una barra invertida tampoco funciona. Entonces la idea es no usar espacio. Genere un archivo temporal con la extensión bat y luego ponga su comando con espacios allí y ejecute el bat. Sin embargo, al ejecutar un comando desde el inicio, no sale cuando está listo, por lo que debe colocar "salir" al final del archivo por lotes.

Esto todavía parece asqueroso.

Por lo tanto, en busca de alternativas, he encontrado que el uso del espacio de cotización en el espacio de "Archivos de programa" realmente funciona con el inicio.

En la clase EXECUTE anterior, cambie el generador de cadenas a los siguientes:

append( "cmd /C start /"Some title/" " ). append( java.lang.System.getProperty( "java.home" ).replaceAll(" ", "/" /"") ). append( java.io.File.separator ). append( "bin" ). append( java.io.File.separator ). append( "java" ). append( " " ). append( new java.io.File( "." ).getAbsolutePath() ). append( java.io.File.separator ). append( CLASS_TO_BE_EXECUTED ).


public abstract class EXECUTE { private EXECUTE() { /* Procedural Abstract */ } public static Process application( final String CLASS_TO_BE_EXECUTED ) { final String EXEC_ARGUMENT = new StringBuilder(). append( java.lang.System.getProperty( "java.home" ) ). append( java.io.File.separator ). append( "bin" ). append( java.io.File.separator ). append( "java" ). append( " " ). append( new java.io.File( "." ).getAbsolutePath() ). append( java.io.File.separator ). append( CLASS_TO_BE_EXECUTED ). toString(); try { return Runtime.getRuntime().exec( EXEC_ARGUMENT ); } catch ( final Exception EXCEPTION ) { System.err.println( EXCEPTION.getStackTrace() ); } return null; } }