我有一个shell脚本,我想从J2EE Web应用程序中触发。
脚本做了很多事情 - 处理,FTP等 - 这是遗留物。
运行需要很长时间。
我想知道什么是最好的方法。我希望用户能够单击链接,触发脚本,并向用户显示一条消息,说明脚本已启动。我希望HTTP请求/响应周期是即时的,不管我的脚本需要很长时间才能运行。
我可以想到三个选择:
以上所有内容都将使用servlet和Runtime.getRuntime()。exec()。
这是在Solaris上使用Oracle的OC4J应用服务器在Java 1.4.2上运行。
请问有没有人对哪个是最不易解决的问题有什么看法?为什么?
或者有没有人有更好的方法?我们有Quartz可用,但我们不希望将shell脚本重新实现为Java进程。
感谢。
答案 0 :(得分:3)
你提到了Quartz所以让我们选择#4选项(IMO当然是最好的):
PS:最大的问题可能是查找文档,这是我能找到的最佳来源:How to use NativeJob?
答案 1 :(得分:2)
我会使用选项3,特别是如果您实际上不需要知道脚本何时完成(或者除了等待进程结束之外还有其他方法可以找到)。
选项1浪费了一个线程,它正在等待脚本完成。选项2似乎是一个坏主意。我不会劫持servlet容器线程。
答案 2 :(得分:2)
您的应用程序是否有必要评估您正在开始的脚本的输出,或者这是一个简单的即发即弃工作?如果不需要,您可以“滥用”Runtime.getRuntime()。exec()将立即返回并继续在后台运行的事实。如果你真的想等待脚本/进程完成,你必须在exec()返回的Process对象上调用waitFor()。
如果您正在开始的进程向stdout或stderr写入任何内容,请确保将这些内容重定向到日志文件或/ dev / null,否则进程将在一段时间后阻塞,因为stdout和stderr可用作InputStreams且有限通过Process对象缓冲功能。
答案 3 :(得分:1)
我对此的处理可能类似于以下内容:
Callable
对象,将其提交给执行程序服务,并将生成的Future
保存在某处(例如,用户会话或UID键控映射返回密钥到用户以后查找,具体取决于要求)。然后立即向用户发送HTTP响应,暗示脚本已启动OK(如果需要,还包括查找键)。Future
的状态返回“仍在运行”的响应,“失败”的响应或“成功的+结果”响应那你只是抬起头来。它有点手工但是根据你的webapp的结构,你可以在某个地方安装这些通用组件。
答案 4 :(得分:1)
如果您的HTTP响应/用户不需要查看脚本的输出,或者知道脚本何时完成,那么您最好的选择是在您提到的某种包装脚本中启动该线程,以便它可以作为一个整体在servlet容器环境之外运行。这意味着您可以免除需要管理容器内的线程,或者在提及时劫持线程等等。
只有当用户需要被告知脚本何时完成和/或监视脚本的输出时,我才会考虑选项1或2.
答案 5 :(得分:0)
对于第二个选项,您可以使用servlet,在响应HTTP请求后,可以使用java.lang.Runtime.exec()来执行脚本。我还建议您查看此处:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
......对于使用它的一些问题和陷阱。
答案 6 :(得分:0)
异步后端进程最强大的解决方案是使用消息队列IMO。最近我使用Spring嵌入式ActiveMQ代理实现了这个,并且绑定了一个生产和使用bean。当需要启动作业时,我的代码会调用生成器,该生成器将消息放入队列。消费者订阅了队列,并在单独的线程中被消息踢入行动。这种方法巧妙地将UI与排队机制(通过生产者)和异步过程(由消费者处理)分开。
请注意,这是一个Java 5,Spring配置的环境,在开发人员计算机上的Tomcat服务器上运行,并在测试/生产计算机上部署到Weblogic。
答案 7 :(得分:0)
您的问题源于这样一个事实:您正在尝试违反J2EE中的“每个请求的单个响应”模型,并在后端任务执行时让最终用户的页面动态更新。
除非您想要介绍基于Ajax的解决方案,否则您必须强制用户浏览器上呈现的页面定期“轮询”服务器以获取信息,直到后端任务完成。
这可以通过以下方式实现:
当J2EE容器收到请求时,产生一个线程,该线程接受会话对象的引用(将用于编写脚本的输出)
初始化响应servlet以编写一个html页面,该页面将包含一个Javascript函数,以定期(每10秒左右)从服务器重新加载页面。
在每个请求上,轮询会话对象以显示步骤1中生成的线程存储的输出
[如果需要,可以添加清理逻辑,以便在线程完成后从会话中删除存储的内容,还可以在会话中设置任何其他标志,用于执行脚本的标记状态转换]
这是实现您想要的一种方式 - 它不是所有方法中最优雅的方法,但它主要是由于需要使用请求/响应模型从服务器异步更新页面内容。
还有其他方法可以实现这一目标,但这实际上取决于您的约束条件的不灵活性。我听说过Direct Web Remoting(虽然我还没玩过它),但值得一看 Developing Applications using Reverse-Ajax