【问题标题】:Execute another jar in a Java program在 Java 程序中执行另一个 jar
【发布时间】:2010-11-22 04:07:15
【问题描述】:

我写了几个简单的 java 应用程序,命名为 A.jar、B.jar。

现在我想编写一个 GUI java 程序,以便用户可以按按钮 A 执行 A.jar 和按钮 B 执行 B.jar。

我还想在我的 GUI 程序中输出运行时进程的详细信息。

有什么建议吗?

【问题讨论】:

  • 不知道为什么这被否决了。向他解释为什么他的假设可能是错误的,但不要对这个问题投反对票。
  • -1 基本的 Java 术语使用不正确,问题非常模糊,留下了很多第二次猜测。考虑用更多细节重新表述您的问题,或者先阅读 Java 类路径和其他基础知识。
  • @grigory:看,这就是您应该首先提出的问题,而不是立即投反对票。在不询问更多信息的情况下投反对票并没有任何好处......
  • @William,很抱歉比你晚了几秒钟点击按钮。我保留对随后发表评论的投票权。看到在没有基本准备和/或努力理解或提出问题的情况下提出的问题令人沮丧。对我来说,投票就像在餐馆里给的小费:根据服务质量,你给的比标准的 12% 多或少。所以让我们同意在这里不同意。
  • @topchef 我迟到了 11 年,但你说“看到在没有基本准备的情况下提出问题令人沮丧......”。然后帮忙解决。解释为什么你投了反对票。否则,您根本无法解决问题。

标签: java jar executable-jar


【解决方案1】:

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

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

>p.mf(p.mf 的内容)

主类:pk.Test

>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));
    }
}

【讨论】:

  • 我认为这个想法是给定对 jar 的访问权限,如何将其添加到类路径中以便从中加载类。
  • 注意:它的工作原理只是因为你的 PATH 中有 java bin,默认的 windows 安装不是这种情况
  • @AVD : A.jar 文件应该保存在哪里?
  • @logan - 在您正在加载程序的目录中。
  • 这种方法会创建一个新的JVM进程还是使用现有的?
【解决方案2】:

如果我理解正确,您似乎想在 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();

缓冲进程的输出总是好的做法。

【讨论】:

  • 此解决方案是否可移植?
  • 谢谢。我试过 exec() func 有 3 个参数,包括“dir”参数,但它不起作用。只有一个,我们只需要将3个文件.jar放在同一个地方
  • 你知道如何获取那个java应用的Runtime对象吗?
  • 我们可以使用更便携的版本,使用 ProcessBuilder 吗?
  • Cannot run program "java": CreateProcess error=2, 系统找不到指定的文件。收到此错误。
【解决方案3】:

如果你是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");
        }
    }
}

【讨论】:

  • 我认为这不能回答 OP 的问题
【解决方案4】:

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

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

请注意,这将使从属 jar 与您的 jar 共享内存空间和类路径,并且可能会造成干扰。如果您不希望这些东西被污染,您还有其他选择,如上所述 - 即:

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

【讨论】:

    【解决方案5】:

    希望这会有所帮助:

    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;
    }
    }
    

    【讨论】:

      【解决方案6】:

      如果程序作为独立运行,以下通过使用批处理文件启动 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
      

      【讨论】:

      • 感谢@Dawood Morris 当您的 jar 需要大量资源(如内存等)时,这真的很有帮助。
      【解决方案7】:

      首先我们创建一个 FirstFileOutput 类,它有一个 main 方法,该方法输出一行到稳定输出和一行到稳定错误。完成所有第一个过程后,我们将再次创建一个 RuntimeExecCheck 类,该类将在启动进程时运行我们的 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();
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-21
        • 2011-01-15
        • 2012-02-28
        • 1970-01-01
        相关资源
        最近更新 更多