我应该如何从Java应用程序运行NodeJS?

我正在编写一个Java库,实际上是一个Clojure库,但是对于这个问题,重要的是它在JVM上运行。 这个库需要执行一些JavaScript。 我尝试过与Nashorn,但我遇到一些限制,可能太难以克服。 作为替代,我想尝试NodeJS。

我希望自己的库是独立的,不依赖于独立运行NodeJS的系统,因此需要特定的部署机制将Java和NodeJS工件放置在正确的位置,由两个不同的networking服务器提取。 但是这种方法带来了一些问题。

我将通过HTTP与NodeJS通话,但是我不希望NodeJS打开特定的端口。 我想find一个随机的未使用的,所以没有碰撞。 我也想控制从NodeJS的日志去,以保持与我的应用程序的其余部分。 最后,我的应用程序应该能够检测到NodeJS何时崩溃并重新运行它或报告错误的信息。

什么是最好的方法来解决这个问题? 有没有任何Java库可以帮助用这种方式pipe理subprocess? 特别是我应该从NodeJS方面做的任何事情(我对NodeJS很陌生,以前从未使用过)。

我最终的解决scheme是使用ProcessBuilder像这样:

(defn create-process-builder [js-engine] (doto (ProcessBuilder. ["node" (:path js-engine) "--port-file" (:port-file js-engine) "--default-ajax-host" (:default-ajax-host js-engine) "--default-ajax-port" (str (:default-ajax-port js-engine))]) .inheritIO)) 

然后调用它开始。 inheritIO会导致它的输出转到当前进程的输出,从而有效地合并stdout和stderr。

最重要的是,NodeJS通过指定0作为端口号打开一个随机端口并将其写入文件:

 (let [app (-> (express) (.use (cookie-parser)) (.get "/" (fn [_req res] (.send res "Universal JavaScript engine for server side pre-rendering single page applications."))) (.get "/render" render)) server (.createServer http app)] (.listen server 0 (fn [] (.writeFile fs (:port-file options) (.-port (.address server))))))))) 

然后由Java方打开(等待它出现):

 (defn get-port-number [js-engine] (or (with-timeout (:start-timeout js-engine) (loop [port-number (read-port-file js-engine)] (if (string/blank? port-number) (if (is-running? js-engine) (do (Thread/sleep 100) (recur (read-port-file js-engine))) (throw (Exception. (str "While waiting for port number, process died: " (:path js-engine))))) port-number))) (throw (Exception. (str "Waited for " (:start-timeout js-engine) " for " (:path js-engine) " to start and report its port number but it timed out."))))) 

在这里有一个相当不错的答案如何在Java中运行JavaScript。 这样的事情可以为你的情况吗? 如果不是这里有一些资源:

  • nodejs中的随机端口您可以在构build过程中再次打开另一个服务来查找打开的端口,或者让您的节点应用程序根据其抓取的端口向您的java服务器发出http请求。
  • 温斯顿是我find的最好的日志库,你不应该有任何问题login到相同的path。
  • Forever和PM2是保持节点运行的公共节点进程pipe理器。 我现在更喜欢永远(不知道为什么)

这听起来像你会在节点内使用很多的CPU。 如果是这种情况,你可能会想使用集群模块 (所以nodejs可以利用多个核心)。 如果你阻塞了事件循环(基于cpu的处理,那么你将只能对每个分叉进程执行1个并发请求)。

Nashorn确实也遇到了一些我也碰到的问题,比如find关于他们的一些API的信息(文档有很多不足之处),以及慢启动。

我会build议,而不是:把你的服务器端渲染作为一个服务,而不是一个subprocess

换句话说,你可以在内部networking上运行一个Node.js实例,并且只允许本地连接(你也可以在任何你想要的地方发送日志)。 然后,您可以使用要呈现的页面向服务发出请求,例如localhost:10015/posts/并让该Node.js应用程序在无头浏览器(使用Phantom或Slimer等内容)中呈现页面。

为了保持你的Node服务器,你可以使用Forever或者supervisord ,并且帮助你更快地获得动力,你可以看看Prerender团队做了什么: https : //github.com/prerender/prerender-node

我一直处于类似的地位,我必须从python脚本运行fortran,所以这是我的两分钱。 用Java中的terminal命令运行你的node.js脚本,如下所示:

 Runtime rt = Runtime.getRuntime(); String[] commands = {"node example.js", "args"}; Process proc = rt.exec(commands); BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream())); // read the output from the command System.out.println("Here is the standard output of the command:\n"); String s = null; while ((s = stdInput.readLine()) != null) { System.out.println(s); } // read any errors from the attempted command System.out.println("Here is the standard error of the command (if any):\n"); while ((s = stdError.readLine()) != null) { System.out.println(s); } 

通过设置,您可以将parameter passing给您的节点程序并获得响应。 虽然我不确定你在使用你的node.js程序,所以不知道这是否有帮助。