在单独的过程中执行Java应用程序
是否可以以与平台无关的方式使用Java应用程序的名称(而不是其位置)在单独的进程中加载Java应用程序?
我知道你可以通过...执行程序
Process process = Runtime.getRuntime().exec( COMMAND );
...这种方法的主要问题是,此类调用是特定于平台的。
理想情况下,我会将方法包装成像...这样简单的东西。
EXECUTE.application( CLASS_TO_BE_EXECUTED );
...,并以CLASS_TO_BE_EXECUTED输入应用程序类的完全限定名称。
9个解决方案
66 votes
这是已提供的其他一些答案的综合。 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表示形式是有意义的,因为无论如何该类都必须位于类路径中。
hallidave answered 2020-07-29T14:02:08Z
42 votes
两个提示:
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)提供了Java可执行文件的路径。
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)帮助您重构当前应用程序的类路径。
那么您的Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)就是(伪代码):
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)
stepancheg answered 2020-07-29T14:01:39Z
6 votes
扩展@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);
}
}
andrej answered 2020-07-29T14:02:28Z
4 votes
这对您来说可能是一个过大的杀伤力,但是Akuma项目可以满足您的需求甚至更多。我是在Kohsuke(Sun的摇滚入门程序员之一)的这篇博客中找到这篇文章的,它非常有用。
StaxMan answered 2020-07-29T14:02:48Z
3 votes
您是否签出了ProcessBuilder API? 从1.5开始可用
[HTTP://Java.孙.com/Java色/6/docs/API/Java/狼/process builder.HTML]
lothar answered 2020-07-29T14:03:13Z
3 votes
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;
}
}
Ande answered 2020-07-29T14:03:28Z
3 votes
您真的必须在本地启动它们吗? 您可以直接调用它们的“主要”方法吗? 关于main的唯一特殊之处是VM启动器会调用它,没有什么可以阻止您自己调用main的。
TofuBeer answered 2020-07-29T14:03:48Z
2 votes
遵循TofuBeer所说的话:您确定真的需要派遣另一个JVM吗? 如今,JVM确实对并发性提供了很好的支持,因此,只需拆分一个或两个新线程即可(不需调用Foo#main(String [])即可获得相对便宜的大量功能)。 查看java.util.concurrent以获取更多信息。
如果您决定分叉,则需要为查找所需资源付出一些复杂性。 也就是说,如果您的应用程序经常更改并且依赖于一堆jar文件,则您需要跟踪所有这些文件,以便将它们传递到类路径arg。 此外,这种方法需要推断(当前正在执行的)JVM的位置(可能不准确)和当前类路径的位置(甚至不太可能准确),具体取决于生成的方式 线程已被调用-jar,jnlp,分解的.classes目录,某些容器等)。
另一方面,链接到静态#main方法也有其陷阱。 静态修饰符有泄漏到其他代码中的讨厌趋势,并且通常被具有设计意识的人所反对。
jasonnerothin answered 2020-07-29T14:04:19Z
1 votes
从Java GUI运行此程序时发生的问题是它在后台运行。因此,您根本看不到命令提示符。
要解决此问题,您必须通过“ cmd.exe”和“ start”运行java.exe。我不知道为什么,但是如果在前面放置“ cmd / c start”,它将在运行时显示命令提示符。
但是,“启动”的问题是,到应用程序的路径中是否有空格(Java exe的路径通常具有该路径C:\ Program Files \ Java \ jre6 \ bin \ java.exe或类似文件),然后启动只会失败,并显示“找不到c:\ Program”
因此,您必须在C:\ Program Files \ Java \ jre6 \ bin \ java.exe周围加上引号现在开始抱怨传递给java.exe的参数:“系统找不到文件-cp。”
用反斜杠转义“ Program Files”中的空间也不起作用。因此,想法是不使用空间。生成一个带bat扩展名的临时文件,然后在其中放置空格的命令并击球。但是,从开始运行蝙蝠,完成后不会退出,因此您必须在批处理文件的末尾添加“退出”。
这似乎仍然令人讨厌。
因此,在寻找替代方案时,我发现在“ Program Files”空间中使用引号空间quote实际上可以与start一起使用。
在上面的EXECUTE类中,将字符串生成器追加到:
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 ).
Matiaan answered 2020-07-29T14:05:11Z