编程语言
首页 > 编程语言> > java – 使用Processbuilder运行jar无法正常工作

java – 使用Processbuilder运行jar无法正常工作

作者:互联网

我有以下代码:

ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "test.jar", Integer.toString( jobId ), Integer.toString( software ), Integer.toString( entryPoint ), application );
pb.directory( new File("/home/userName/TestBSC") );
Process proc = pb.start();

使用此命令从终端运行jar文件时:

java -jar test.jar 135 3 3 appName

然后它就像一个魅力. jar会在我的数据库中推送一些内容,所以我发现它正在运行.但是当我使用上面提到的processBuilder代码从我的JavaServlet中执行它时,我没有在我的数据库中获得任何数据,也没有任何错误.

但是进程本身正在运行,我在终端中用“ps ax”检查了它.所以我想知道这里的区别在哪里?我究竟做错了什么?

有人有想法吗?

编辑:更多代码:

ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "test.jar", Integer.toString( jobId ), Integer.toString( software ), Integer.toString( entryPoint ), application );
pb.directory( new File("/home/userName/TestBSC") );
Process proc = pb.start();

System.out.println( "Job running" );
proc.waitFor(); // wait until jar is finished
System.out.println( "Job finished" );

InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();

byte result[] = new byte[ in.available() ];
in.read( result, 0, result.length );
System.out.println( new String( result ) );

byte error[] = new byte[ err.available() ];
err.read( error, 0, error.length );
System.out.println( new String( error ) );

更新:

我试着调用shell脚本而不是jar.所以我用java文件中的processbuilder调用了一个shell脚本.

我的shell脚本执行此操作:

java -jar test.jar "$1" "$2" "$3" "$4"

好吧它仍然无法正常工作.所以我尝试了这个:

gnome-terminal -x java -jar test.jar "$1" "$2" "$3" "$4"

突然它有效!!但是它打开了gnome-terminal,它执行jar文件.

所以我想知道,这可能与eclipse中没有显示的输出有关吗?我真的不明白.这是一个很好的解决方法.但是我真的希望每次执行jar时都不会打开终端.

解决方法:

首先,我无法重现您的问题所以这个答案将完全基于文档.

By default, the created subprocess does not have its own terminal or
console. All its standard I/O (i.e. stdin, stdout, stderr) operations
will be redirected to the parent process, where they can be accessed
via the streams obtained using the methods getOutputStream(),
getInputStream(), and getErrorStream(). The parent process uses these
streams to feed input to and get output from the subprocess. Because
some native platforms only provide limited buffer size for standard
input and output streams, failure to promptly write the input stream
or read the output stream of the subprocess may cause the subprocess
to block, or even deadlock.

java.lang.Process Documentation

基本上,这告诉您需要正确处理外部进程的流,否则可能会导致某些平台出现死锁.这意味着如果我们运行的命令产生一些输出,你必须读取该输出.

那么让我们来看看你的代码;你正在调用process.waitFor()来等待进程完成但事情是你的进程无法完成而没有你读取/消耗它的输出因此你正在创建一个死锁.

如何克服这个问题:

> Method正在使用InputStreamConsumerThread来正确处理输入/错误流;

public class InputStreamConsumerThread extends Thread
{
  private InputStream is;
  private boolean sysout;
  private StringBuilder output = new StringBuilder();

  public InputStreamConsumerThread (InputStream is, boolean sysout)
  {
    this.is=is;
    this.sysout=sysout;
  }

  public void run()
  {
    try(BufferedReader br = new BufferedReader(new InputStreamReader(is)))
    {
      for (String line = br.readLine(); line != null; line = br.readLine())
      {
        if (sysout)
          System.out.println(line);    
        output.append(line).append("\n");
      }
    }
  }
  public String getOutput(){
    return output.toString();
  }
}

你的代码将是;

String systemProperties = "-Dkey=value";    
ProcessBuilder pb = new ProcessBuilder( "java", systemProperties, "-jar", "test.jar", Integer.toString( jobId ), Integer.toString( software ), Integer.toString( entryPoint ), application );
pb.directory( new File("/home/userName/TestBSC") );
Process proc = pb.start();

InputStreamConsumerThread inputConsumer = 
     new InputStreamConsumerThread(proc.getInputStream(), true);
InputStreamConsumerThread errorConsumer = 
     new InputStreamConsumerThread(proc.getErrorStream(), true);

inputConsumer.start();
errorConsumer.start();

System.out.println( "Job running" );
proc.waitFor(); // wait until jar is finished
System.out.println( "Job finished" );

String processOutput = inputConsumer.getOutput();
String processError = errorConsumer.getOutput();

if(!processOutput.isEmpty()){
    //there were some output
}

if(!processError.isEmpty()){
    //there were some error
}

>方法是使用ProcessBuilder重定向输出.如果您只是希望子进程与父进程使用相同的输入/输出流,则可以像这样使用ProcessBuilder.Redirect.INHERIT;

ProcessBuilder pb = new ProcessBuilder( "java", "-jar", "test.jar", Integer.toString( jobId ), Integer.toString( software ), Integer.toString( entryPoint ), application );
pb.directory( new File("/home/userName/TestBSC") );
pb.redirectErrorStream(true); // redirect error stream to output stream
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process proc = pb.start();

System.out.println( "Job running" );
//since process builder will handle the streams for us
//we can call waitFor() safely
proc.waitFor(); 
System.out.println( "Job finished" );

>方法正在使用第三方库.如果你不想使用ProcessBuilder和消费者自己解决问题,我知道有两个库可以非常好地处理创建子流程.

A low-overhead, non-blocking I/O, external Process execution
implementation for Java. It is a replacement for
java.lang.ProcessBuilder and java.lang.Process.

Have you ever been annoyed by the fact that whenever you spawn a
process in Java you have to create two or three “pumper” threads (for
every process) to pull data out of the stdout and stderr pipes and
pump data into stdin?
If your code starts a lot of processes you can
have dozens or hundreds of threads doing nothing but pumping data.

NuProcess uses the JNA library to use platform-specific native APIs to
achive non-blocking I/O on the pipes between your Java process and the
spawned processes.

NuProcess

There are many approaches to take when running external processes from
Java. There are the JRE options such as the Runtime.exec() and
ProcessBuilder. Also there is the Apache Commons Exec. Nevertheless we
created yet another process library (YAPL).

Some of the reasons for this crazy endeavour

Improved handling of streams Reading/writing to streams Redirecting
stderr to stdout
Improved handling of timeouts Improved checking of
exit codes Improved API One liners for quite complex usecases One
liners to get process output into a String Access to the Process
object available Support for async processes ( Future ) Improved
logging with SLF4J API Support for multiple processes

ZT Process Executor

此外,Java的Process API还有其他陷阱,请查看此JavaWorld文章以获取更多信息When Runtime.exec() won’t.

标签:java,jar,processbuilder
来源: https://codeday.me/bug/20190608/1199908.html