Apache Commons Exec 教程

在这一点上,我们可以安全地假设您想从 Java 应用程序中启动一些子进程,并且您在这里花了一些时间来正确地完成它。

在这一点上,我们可以安全地假设您想从 Java 应用程序中启动一些子进程,并且您在这里花了一些时间来正确地完成它。您查看 Commons Exec 并认为“哇 - 调用 Runtime.exec() 很容易,而 Apache 人员正在用大量代码浪费他们和我的时间”。

好吧,我们通过艰难的方式(在我的例子中不止一次)了解到使用普通的 Runtime.exec() 可能是一种痛苦的经历。因此,邀请您深入研究 commons-exec 并以简单的方式查看艰难的课程......

驯服你的第一个过程

让我们看一个真实的例子 - 我们想从您的 Java 应用程序中打印 PDF 文档。谷歌搜索一段时间后,结果证明是一个小问题,使用 Adobe Acrobat 似乎是一个不错的选择。

假设在路径中找到 Acrobat Reader,Windows 下的命令行应该类似于 “AcroRd32.exe /p /h file”。

String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);

您成功打印了第一个 PDF 文档,但最后抛出异常 - 发生了什么?糟糕,Acrobat Reader 在成功时返回退出值“1”,这通常被视为执行失败。所以我们必须调整我们的代码来修复这个奇怪的行为 —— 我们定义了 “1” 的退出值被认为是成功执行。

String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
int exitValue = executor.execute(cmdLine);

看门狗或没有看门狗

您愉快地打印了一段时间,但现在您的应用程序阻塞了 - 您的打印子进程因某些明显或不那么明显的原因而挂起。开始很容易,但如果Acrobat Reader失控,告诉你打印失败是因为缺纸,该怎么办呢?!幸运的是,Commons-exec提供了一个看门狗来为您完成这项工作。下面是改进后的代码,它会在60秒后终止一个失控的进程。

String line = "AcroRd32.exe /p /h " + file.getAbsolutePath();
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);

引用是你的朋友

嗯,代码运行了很长一段时间,直到一位新客户抱怨没有打印任何文件。花了半天时间才发现无法打印以下文件 ‘C:\Document and Settings\Documents\432432.pdf’。由于空格的原因,并且没有进一步引用,命令行实际上分成了以下代码片段

AcroRd32.exe /p /h C:\Document And Settings\documents\432432.pdf

作为一种快速修复方法,我们添加了双引号,告诉 commons-exec 将该文件作为单个命令行参数处理,而不是将其分成几个部分。

String line = "AcroRd32.exe /p /h \"" + file.getAbsolutePath() + "\"";
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);

增量构建命令行

前面的问题源于Commons-exec试图将单个命令行字符串拆分为字符串数组(考虑单引号和双引号)。

归根结底,这很容易出错,所以我们建议增量地构建命令行-根据同样的推理,Ant文档不建议将单个命令行传递给exec目标(请参阅exec任务的弃用命令属性)

Map map = new HashMap();
map.put("file", new File("invoice.pdf"));
CommandLine cmdLine = new CommandLine("AcroRd32.exe");
cmdLine.addArgument("/p");
cmdLine.addArgument("/h");
cmdLine.addArgument("${file}");
cmdLine.setSubstitutionMap(map);
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(1);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
int exitValue = executor.execute(cmdLine);

请注意,我们正在传递一个用于扩展命令行参数的“java.io.File”实例-这允许动态转换结果文件名以匹配您的操作系统。

取消阻止您的执行

到目前为止,我们有一个工作的例子,但它不足以用于生产-因为它是阻塞的。

您的工作线程将阻塞,直到打印进程完成或被监视程序终止。

因此,异步执行打印作业将会起到作用。

在本例中,我们创建了一个‘ExecuteResultHandler’实例,并将其传递给‘Executor’实例,以便异步执行流程。

“result tHandler”拾取任何违规异常或进程退出代码。

CommandLine cmdLine = new CommandLine("AcroRd32.exe");
cmdLine.addArgument("/p");
cmdLine.addArgument("/h");
cmdLine.addArgument("${file}");
HashMap map = new HashMap();
map.put("file", new File("invoice.pdf"));
commandLine.setSubstitutionMap(map);

DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();

ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000);
Executor executor = new DefaultExecutor();
executor.setExitValue(1);
executor.setWatchdog(watchdog);
executor.execute(cmdLine, resultHandler);

// some time later the result handler callback was invoked so we
// can safely request the exit value
int exitValue = resultHandler.waitFor();

「资源下载」

我们一定要给自己提出这样的任务:第一,学习,第二是学习,第三还是学习。 —— 列宁
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号