从Node.js应用程序中调用Java程序

13

根据我所读的,有几种方法可以在 node.js 应用程序中运行 java 文件。其中一种方法是生成子进程:(java 代码已被打包在可执行的 jar 中,并包含依赖项。)

var exec = require('child_process').exec, child;    
child = exec('java -jar file.jar arg1 arg2',
      function (error, stdout, stderr){
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
        if(error !== null){
          console.log('exec error: ' + error);
        }
    });
另一种方法是使用java-npm模块(链接),它是JNI的包装器(这将允许我创建对象,设置和获取属性,运行方法)。
在生产环境中,当我想要我的node.js (Express)服务器调用一个Java程序(它只是将图像保存到本地目录)时,请告诉我哪种方法是更好的(就最佳实践而言)。此外,我还需要传递一长串参数main类,但在命令行上完成有点困难。我应该让Java程序从输入文件中读取吗?

如果您的输入足够复杂,我建议创建POJOs来表示您的输入数据,并使用Jackson YAML工厂将其反序列化为JSON或YAML文件(YAML也可以解析JSON)。然后使用Args4J并接受JSON作为文件选项,以及具有 -i 的输入选项,告诉您从stdin读取输入,以便JSON可以从另一个程序进行管道传输。这使他们拥有一个模板,他们可以通过简单的令牌替换来执行,然后将其导入到您的程序中。或者你也可以从node同样做到这一点。 - Novaterata
经过进一步的思考,似乎通过标准输出/输入将数据发送到Java程序会更有意义。创建临时文件然后从Java程序中加载它并不是必要的,还会引入IO瓶颈。 - Novaterata
5个回答

6
1)如果你使用exec,你将运行整个程序,而如果你使用JNI接口,你将能够直接与jar中的库和类交互,并做一些像调用单个函数或创建一个类实例的事情。然而,如果你不需要这样的功能,我认为使用exec更简单,速度也更快。听起来你只是想将Java应用程序作为独立进程运行,并记录应用程序是否成功完成或出现错误。我认为最好只使用exec。以这种方式执行子进程也更适合调试,有时调试JNI错误可能非常困难。
2)至于是否从文件中读取参数,是的,通常最好从某种类型的文件中读取,而不是直接传递参数。它不容易出现人为错误(即每次键入参数),并且可配置性更强。如果像QA工程师这样的人只需要编辑配置文件来交换选项,他们就不需要理解你的整个代码库来测试它。个人对于我编写的每个Java程序都使用配置文件。

0
我们可以通过制作 .jar 文件并在 shell 中使用命令运行该文件来运行整个 Java 项目。为了从 Node.js 项目中运行 Java 代码,我们知道该项目可能是 Java 和 JS 模块的混合体。在 Node.js 中调用 exec() 函数创建子进程以执行具有运行 .sh 文件的命令的 shell 文件,并且还可以从用户处传递一些参数。例如:
let fileName = 'someFile.txt';
let userName = 'Charlie Angle'; 
exec(`sh run.sh --context_param
paramFilePath="./storage/${fileName}" --context_param userName="${userName}"`, (error, stdout, stderr) => {// Some code based on execution of above command})

0

我可以传递不是String类型的参数吗(比如一个Array)? - raul
我刚刚尝试了一下。我传入了 ['asd', 'qwe', 'zxc'],并将其作为逗号分隔的字符串"asd,qwe,zxc"返回,很容易通过逗号进行拆分并转换为数组。 - Gyunesh Shefkedov
是的,但有些元素中也可能有逗号。 - raul

0
针对这种问题,您需要按照以下方式进行处理:
  • 在我的语言/框架中是否有一个合理的方法来运行带参数的进程?
  • 在我的语言/框架中是否有一个合理的方法来处理程序的输出?
从经验上看,处理进程参数的一个好方法是将它们作为(字符串)数组传递。这样做的优点是您不必诉诸于不必要的字符串插值和操作。这也更易读,这在这个问题设置中是一个加分项。
处理输出的一个好方法是使用监听器/事件模型。这样,您可以适当地响应事件,而不是为stderr和stdout编写if块。同样,这使得事情更易读,并让您以更可维护的方式处理输出。
如果您进一步深入,还需要解决如何将环境变量注入到目标程序中的问题。例如,您可能希望在将来使用调试器或更少的内存运行Java,因此您的解决方案也需要考虑这一点。

这只是解决这种问题的一种方法。如果您使用的是Node平台,请查看Child Process,它支持所有这些技术。


0

您可以使用模块node-java-caller简单地调用Java命令,包括类路径和参数,它嵌入了调用spawn的调用,并且如果系统上没有安装Java,则会自动安装。

https://github.com/nvuillam/node-java-caller


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接