在 Tomcat 容器中启动进程时遇到一个奇怪的错误。如何解决?

Facing a strange bug when starting a process in a Tomcat container. How to resolve it?

我创建了一个 Web 应用程序来管理用户创建的任意作业。一项工作将一些文件复制到另一个文件夹并启动外部程序。外部程序使用批处理文件启动,批处理文件设置一些变量并启动另一个 Java 程序,将文件提交到服务器。我这样启动批处理文件:

final ProcessBuilder pb = new ProcessBuilder("path/to/batch");

pb.directory("parent/folder/of/batch");

final Process p = pb.start();

p.waitFor();

批处理文件包含以下内容:

set CLASSPATH=%CLASSPATH%;<external-program.jar>
set PATH=%PATH%;C:\Program Files\Java\jre7\bin

@echo off
set puser=****
set ppsw=****

java -jar <external-program.jar> %puser% %ppsw%

进程启动但未完成,我的 web 应用程序被阻止。如果我手动启动批处理文件,一切都很好。现在真正奇怪的是:如果我关注 Tomcat window 并使用 Ctrl-C 关闭服务器,该过程将继续工作并以预期结果结束。怎么会这样?

最后的日志是:

[2015-01-14 14:31:39,514]DEBUG   860[main] - org.apache.commons.httpclient.Wire.wire(Wire.java:70) - >> "GET /something HTTP/1.1[\r][\n]"
[2015-01-14 14:31:39,514]DEBUG   860[main] - org.apache.commons.httpclient.Wire.wire(Wire.java:70) - >> "Authorization: Basic ****[\r][\n]"
[2015-01-14 14:31:39,514]DEBUG   860[main] - org.apache.commons.httpclient.Wire.wire(Wire.java:70) - >> "User-Agent: Jakarta Commons-HttpClient/3.1[\r][\n]"
[2015-01-14 14:31:39,514]DEBUG   860[main] - org.apache.commons.httpclient.Wire.wire(Wire.java:70) - >> "Host: some.host[\r][\n]"
[2015-01-14 14:31:39,514]DEBUG   860[main] - org.apache.commons.httpclient.Wire.wire(Wire.java:70) - >> "[\r][\n]"

所以我认为它正在向服务器发出请求然后被阻止。不知何故,servlet 容器在其中发挥了作用。我也尝试使用 Jetty,但问题仍然存在。使用 80 以外的端口也不能解决问题。

我很困惑,如果有人能帮助我,我会很高兴。

P.S.: 我在 Windows 7 x64.

上使用 Tomcat 8.0.15

默认情况下,如果您不重定向任何描述符(stdin、stdout 或 stderr;或 Windows 上的任何等效项),它们将与创建它们的进程共享它——在您的情况下, Tomcat.

可能是该进程尝试写入 stdout、stderr 或两者,并且阻止尝试写入 it/them。

尝试重定向到一个文件,例如,因为使用 ProcessBuilder 你可以这样做 (stdout, stderr)。

此外,检查 .waitFor() 的 return 值:这将是进程的退出值。由于您调用了一个 jar,因此 main() 抛出的任何未捕获的异常都会使进程以代码 1 退出(这就是为什么当您自己编写程序时不应该使用此退出代码!)。