Java应用程序是否可以使用其名称(而不是其位置)以独立于平台的方式加载到单独的进程中?
我知道你可以通过...执行一个程序
Process process = Runtime.getRuntime().exec( COMMAND );
...这种方法的主要问题是这种调用是特定于平台的.
理想情况下,我将方法包装成简单的方法......
EXECUTE.application( CLASS_TO_BE_EXECUTED );
...并传入应用程序类的完全限定名称CLASS_TO_BE_EXECUTED
.
这是已经提供的一些其他答案的综合.Java系统属性提供了足够的信息来提供java命令和类路径的路径,我认为这是一种独立于平台的方式.
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.getName(); ProcessBuilder builder = new ProcessBuilder( javaBin, "-cp", classpath, className); Process process = builder.inheritIO().start(); process.waitFor(); return process.exitValue(); } }
你会像这样运行这个方法:
int status = JavaProcess.exec(MyClass.class);
我认为传递实际的类而不是名称的String表示是有意义的,因为类必须在类路径中才能使其工作.
两个提示:
System.getProperty("java.home") + "/bin/java"
为您提供java可执行文件的路径.
((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURL()
帮助您重建当前应用程序的类路径.
然后你EXECUTE.application
就是(伪代码):
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)
扩展@ stepancheg的答案,实际代码看起来如此(以测试的形式).
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); } }