在 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 退出(这就是为什么当您自己编写程序时不应该使用此退出代码!)。
我创建了一个 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 退出(这就是为什么当您自己编写程序时不应该使用此退出代码!)。