在 Java 程序中执行另一个 jar

我已经编写了几个简单的 Java 应用程序,命名为 A.jar,B.jar。

现在我想编写一个 GUI java 程序,这样用户就可以按下按钮 A 来执行 A.jar,按钮 B 来执行 B.jar。

此外,我想输出在我的 GUI 程序的运行时过程的细节。

有什么建议吗?

138130 次浏览

不可执行。实例化类或调用任何静态方法。

编辑: 在创建 JAR 时添加 Main-Class 条目。

> p.mf (内容)

主要类别: pk。测试

>Test.java


package pk;
public class Test{
public static void main(String []args){
System.out.println("Hello from Test");
}
}

使用 Process 类及其方法,

public class Exec
{
public static void main(String []args) throws Exception
{
Process ps=Runtime.getRuntime().exec(new String[]{"java","-jar","A.jar"});
ps.waitFor();
java.io.InputStream is=ps.getInputStream();
byte b[]=new byte[is.available()];
is.read(b,0,b.length);
System.out.println(new String(b));
}
}

如果我理解正确的话,看起来你想在 java GUI 应用程序内部的一个单独的进程中运行 jar。

要做到这一点,你可以使用:

// Run a java app in a separate system process
Process proc = Runtime.getRuntime().exec("java -jar A.jar");
// Then retreive the process output
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();

缓冲过程的输出总是一种好的做法。

如果你是 java 1.6,那么下面的步骤也可以做到:

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;


public class CompilerExample {


public static void main(String[] args) {
String fileToCompile = "/Users/rupas/VolatileExample.java";


JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();


int compilationResult = compiler.run(null, null, null, fileToCompile);


if (compilationResult == 0) {
System.out.println("Compilation is successful");
} else {
System.out.println("Compilation Failed");
}
}
}

如果 jar 在您的类路径中,并且您知道它的 Main 类,那么您可以直接调用 Main 类。以 DITA-OT 为例:

import org.dita.dost.invoker.CommandLineInvoker;
....
CommandLineInvoker.main('-f', 'html5', '-i', 'samples/sequence.ditamap', '-o', 'test')

注意,这将使从属 jar 与 jar 共享内存空间和类路径,并可能导致所有干扰。如果你不想那些东西被污染,你还有其他选择,就像上面提到的那样——即:

  • 创建一个包含 jar 的新 ClassLoader。这样更安全; 如果您知道将要使用外来的 jar,那么您至少可以将新 jar 的知识与核心类加载器隔离开来。我们的插件系统就是这么做的; 主应用程序是一个带有 ClassLoader 工厂的小外壳,一个 API 的副本,并且知道真正的应用程序是第一个应该构建 ClassLoader 的插件。插件是一对压缩在一起的 jar ——接口和实现。ClassLoader 都共享所有接口,而每个 ClassLoader 只知道自己的实现。堆栈有点复杂,但它通过了所有测试,工作得很好。
  • 使用 Runtime.getRuntime.exec(...)(它完全隔离 jar,但具有正常的“查找应用程序”、“正确转义字符串”、“特定于平台的卧槽”和运行系统命令的“ OMG 系统线程”缺陷。

希望这能有所帮助:

public class JarExecutor {


private BufferedReader error;
private BufferedReader op;
private int exitVal;


public void executeJar(String jarFilePath, List<String> args) throws JarExecutorException {
// Create run arguments for the


final List<String> actualArgs = new ArrayList<String>();
actualArgs.add(0, "java");
actualArgs.add(1, "-jar");
actualArgs.add(2, jarFilePath);
actualArgs.addAll(args);
try {
final Runtime re = Runtime.getRuntime();
//final Process command = re.exec(cmdString, args.toArray(new String[0]));
final Process command = re.exec(actualArgs.toArray(new String[0]));
this.error = new BufferedReader(new InputStreamReader(command.getErrorStream()));
this.op = new BufferedReader(new InputStreamReader(command.getInputStream()));
// Wait for the application to Finish
command.waitFor();
this.exitVal = command.exitValue();
if (this.exitVal != 0) {
throw new IOException("Failed to execure jar, " + this.getExecutionLog());
}


} catch (final IOException | InterruptedException e) {
throw new JarExecutorException(e);
}
}


public String getExecutionLog() {
String error = "";
String line;
try {
while((line = this.error.readLine()) != null) {
error = error + "\n" + line;
}
} catch (final IOException e) {
}
String output = "";
try {
while((line = this.op.readLine()) != null) {
output = output + "\n" + line;
}
} catch (final IOException e) {
}
try {
this.error.close();
this.op.close();
} catch (final IOException e) {
}
return "exitVal: " + this.exitVal + ", error: " + error + ", output: " + output;
}
}

如果程序作为独立程序运行,以下方法可以通过批处理文件启动 jar:

public static void startExtJarProgram(){
String extJar = Paths.get("C:\\absolute\\path\\to\\batchfile.bat").toString();
ProcessBuilder processBuilder = new ProcessBuilder(extJar);
processBuilder.redirectError(new File(Paths.get("C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt").toString()));
processBuilder.redirectInput();
try {
final Process process = processBuilder.start();
try {
final int exitStatus = process.waitFor();
if(exitStatus==0){
System.out.println("External Jar Started Successfully.");
System.exit(0); //or whatever suits
}else{
System.out.println("There was an error starting external Jar. Perhaps path issues. Use exit code "+exitStatus+" for details.");
System.out.println("Check also C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt file for additional details.");
System.exit(1);//whatever
}
} catch (InterruptedException ex) {
System.out.println("InterruptedException: "+ex.getMessage());
}
} catch (IOException ex) {
System.out.println("IOException. Faild to start process. Reason: "+ex.getMessage());
}
System.out.println("Process Terminated.");
System.exit(0);
}

在 batchfile.bat 中,我们可以说:

@echo off
start /min C:\path\to\jarprogram.jar

首先,我们确认一个类 FirstFileOutput 具有一个 main 方法,该方法输出一行到稳定输出,输出一行到稳定错误。在所有第一个过程中,我们将再次创建一个类 RuntimeExecCheck,它将在 start for process 中运行 FirstFileOutput 类,然后 RuntimeExecCheck 类将读取稳定的输出,稳定的错误将从 FirstFileOutput 和输出中出现。

package check;


public class FirstFileOutput{


public static void main(String[] args) {
System.out.println("This is output to stable output");
System.err.println("This is output to stable error");
}
}






package check;


import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;


public class RuntimeExecCheck {


public static void main(String[] args) {
try {
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec("java -classpath C:\\projects\\workspace\\check\\bin check.FirstFileOutput");
InputStream inputStream = process.getInputStream();
InputStreamReader isr = new InputStreamReader(inputStream);
InputStream errorStream = process.getErrorStream();
InputStreamReader esr = new InputStreamReader(errorStream);


int n1;
char[] c1 = new char[1024];
StringBuffer stableOutput = new StringBuffer();
while ((n1 = isr.read(c1)) > 0) {
stableOutput.append(c1, 0, n1);
}
System.out.println("Stable Output: " + stableOutput.toString());


int n2;
char[] c2 = new char[1024];
StringBuffer stableError = new StringBuffer();
while ((n2 = esr.read(c2)) > 0) {
stableError.append(c2, 0, n2);
}
System.out.println("Stable Error: " + stableError.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}