在单独的进程中执行Java应用程序

在单独的进程中执行Java应用程序,java,process,exec,Java,Process,Exec,Java应用程序能否以独立于平台的方式,使用其名称(而不是位置)在单独的进程中加载 我知道你可以通过 Process process = Runtime.getRuntime().exec( COMMAND ); 。。。这种方法的主要问题是这样的调用是特定于平台的 理想情况下,我会将一个方法包装成像 EXECUTE.application( CLASS_TO_BE_EXECUTED ); 。。。并将应用程序类的完全限定名传递为要执行的类您真的必须以本机方式启动它们吗?你能直接调用他们的“主

Java应用程序能否以独立于平台的方式,使用其名称(而不是位置)在单独的进程中加载

我知道你可以通过

Process process = Runtime.getRuntime().exec( COMMAND );
。。。这种方法的主要问题是这样的调用是特定于平台的


理想情况下,我会将一个方法包装成像

EXECUTE.application( CLASS_TO_BE_EXECUTED );

。。。并将应用程序类的完全限定名传递为
要执行的类

您真的必须以本机方式启动它们吗?你能直接调用他们的“主要”方法吗?main的唯一特殊之处是VM启动器调用它,没有什么可以阻止您自己调用main。

您真的必须以本机方式启动它们吗?你能直接调用他们的“主要”方法吗?main的唯一特殊之处是VM启动器调用它,没有任何东西可以阻止您自己调用main。

两个提示:

System.getProperty(“java.home”)+“/bin/java”
提供了指向java可执行文件的路径

((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURL()帮助您重建当前应用程序的类路径

那么您的
EXECUTE.application
就是(伪代码):

Process.exec(javaExecutable,“-classpath”,url.join(“:”),类将被执行)
两个提示:

System.getProperty(“java.home”)+“/bin/java”
提供了指向java可执行文件的路径

((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURL()帮助您重建当前应用程序的类路径

那么您的
EXECUTE.application
就是(伪代码):


Process.exec(javaExecutable,“-classpath”,url.join(“:”),CLASS\u TO\u BE\u EXECUTED)

下面是TofuBeer说过的话:你确定你真的需要另一个JVM吗?现在JVM对并发性有很好的支持,因此您可以通过拆分一两个新线程(可能需要也可能不需要调用Foo#main(String[]),以相对便宜的价格获得很多功能。有关更多信息,请查看java.util.concurrent

如果您决定使用fork,那么您将面临与查找所需资源相关的一点复杂性。也就是说,如果您的应用程序经常更改,并且依赖于一堆jar文件,那么您需要跟踪它们,以便将它们传递给classpath参数。此外,这种方法需要推断(当前正在执行的)JVM的位置(可能不准确)和当前类路径的位置(更不可能准确,这取决于调用生成线程的方式—jar、jnlp、exploded.classes dir、某些容器等)


另一方面,链接到静态的主要方法也有其缺陷。静态修饰符有泄漏到其他代码中的严重倾向,并且通常受到有设计意识的人的反对。

下面是TofuBeer不得不说的话:你确定你真的需要另一个JVM吗?现在JVM对并发性有很好的支持,因此您可以通过拆分一两个新线程(可能需要也可能不需要调用Foo#main(String[]),以相对便宜的价格获得很多功能。有关更多信息,请查看java.util.concurrent

如果您决定使用fork,那么您将面临与查找所需资源相关的一点复杂性。也就是说,如果您的应用程序经常更改,并且依赖于一堆jar文件,那么您需要跟踪它们,以便将它们传递给classpath参数。此外,这种方法需要推断(当前正在执行的)JVM的位置(可能不准确)和当前类路径的位置(更不可能准确,这取决于调用生成线程的方式—jar、jnlp、exploded.classes dir、某些容器等)


另一方面,链接到静态的主要方法也有其缺陷。静态修饰符有泄漏到其他代码中的严重趋势,并且通常受到设计人员的反对。

您是否查阅了ProcessBuilderAPI?从1.5开始提供


您是否查看了ProcessBuilderAPI?从1.5开始提供


这是对已经提供的一些其他答案的综合。Java系统属性提供了足够的信息,可以找到Java命令的路径和类路径,我认为这是一种独立于平台的方式

public final class JavaProcess {

    private JavaProcess() {}        

    public static int exec(Class klass, List<String> args) 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.getName();

        List<String> command = new LinkedList<String>();
        command.add(javaBin);
        command.add("-cp");
        command.add(classpath);
        command.add(className);
        if (args != null) {
            command.addAll(args);
        }

        ProcessBuilder builder = new ProcessBuilder(command);

        Process process = builder.inheritIO().start();
        process.waitFor();
        return process.exitValue();
    }

}

我认为传入实际的类而不是名称的字符串表示是有意义的,因为无论如何,类必须位于类路径中才能起作用。

这是对已经提供的一些其他答案的综合。Java系统属性提供了足够的信息,可以找到Java命令的路径和类路径,我认为这是一种独立于平台的方式

public final class JavaProcess {

    private JavaProcess() {}        

    public static int exec(Class klass, List<String> args) 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.getName();

        List<String> command = new LinkedList<String>();
        command.add(javaBin);
        command.add("-cp");
        command.add(classpath);
        command.add(className);
        if (args != null) {
            command.addAll(args);
        }

        ProcessBuilder builder = new ProcessBuilder(command);

        Process process = builder.inheritIO().start();
        process.waitFor();
        return process.exitValue();
    }

}

我认为传入实际的类而不是名称的字符串表示是有意义的,因为无论如何,类必须在类路径中才能起作用。

这对您来说可能有点过分,但可以满足您的需要。
我在Kohsuke(Sun的rock start程序员之一)的博客上找到了它,这是一个非常有用的博客。

这对你来说可能有些过分,但它做了你想做的事情,甚至更多。
我在Kohsuke(Sun的rock start程序员之一)的博客上发现了它,非常有用。

从java GUI运行它时出现的一个问题是它在后台运行。 因此,您根本看不到命令提示

要解决这个问题,必须通过“cmd.exe”和“start”运行java.exe。 我不知道为什么,但是如果你把“cmd/cstart”放在前面,它会在运行时显示命令提示符

但是,“开始”的问题是,如果在到
int status = JavaProcess.exec(MyClass.class, args);
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 ).
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.getName()
                // main class arguments go here
        )
                .inheritIO()
                .start();
        int exitCode = process.waitFor();
        System.out.println("process stopped with exitCode " + exitCode);
    }
}