在nodejs中使用Java方法
JSON-RPC 2.0是一种轻量级、无状态的远程过程调用(RPC)协议,使用JSON作为数据交换格式。表1请求对象字段名类型必填说明jsonrpcstring是固定为 "2.0"methodstring是方法名params否参数id否请求标识符代码10请求对象示例"id": 1表2响应对象字段名类型必填说明jsonrpcstring是固定为 "2.0"resultany否结果error错误对象否
将Java类封装成JSON RPC 2.0服务,通过标准输入输出流发布。在nodejs中启动服务子进程,读写标准输入输出流,实现接口调用。
1. 方案
将现有Java库封装为JSON-RPC 2.0服务。假设现有Javalib.jar库,提供Javalib类和方法 String hello(String name) 。编写封装类,将Java方法封装成JSON-RPC 2.0接口。
代码1 将Java方法封装成JSON-RPC 2.0接口
private JSONObject serve(JSONObject request) {
String method = request.getString("method");
int id = request.getInt("id");
JSONObject params = request.getJSONObject("params");
JSONObject response = new JSONObject();
response.put("jsonrpc", "2.0");
response.put("id", id);
JSONObject error = new JSONObject();
switch (String.valueOf(method)) {
case "hello": {
String name = params.getString("name");
Javalib javalib = new Javalib();
String result = javalib.hello(name);
response.put("result", result);
break;
}
case "exit":
response.put("result", "exit");
running = false;
break;
default:
error.put("code", -32601);
error.put("messsage", "method not found");
response.put("error", error);
break;
}
return response;
}
编写命令行程序,通过标准输入输出发布JSON-RPC 2.0服务。
代码2 通过标准输入输出发布JSON-RPC 2.0服务
private String serve(String jsonStr) {
JSONObject request = new JSONObject(jsonStr);
JSONObject response = serve(request);
return response.toString();
}
public static void main(String[] args) throws IOException {
JsonRpcServer server = new JsonRpcServer();
Scanner scanner = new Scanner(System.in);
while (server.running) {
String jsonStr = scanner.nextLine();
System.out.println(server.serve(jsonStr));
}
}
在nodejs中启动服务程序,通过标准输入输出实现远程调用
代码3 在nodejs中通过标准输入输出实现远程调用
import { spawn } from 'child_process';
class JsonRpcClient {
constructor() {
this.counter = 0;
this.listeners = new Map();
this.javaProcess = spawn('java', ['-cp', 'Javalib.jar;json-20250517.jar;.', 'JsonRpcServer']);
this.javaProcess.stdout.on('data', (data) => {
const jsonStr = data.toString();
try {
const { id, result } = JSON.parse(jsonStr);
if (this.listeners.has(id)) {
this.listeners.get(id)(jsonStr);
this.listeners.delete(id);
}
} catch (err) {
console.error('Failed to parse response:', err);
}
});
this.javaProcess.stderr.on('data', (data) => {
console.error('Java process error:', data.toString());
});
}
async call(method, params = {}) {
const id = ++this.counter;
const request = {
jsonrpc: "2.0",
id,
method,
params,
};
const jsonStr = JSON.stringify(request);
console.log(`发送 ${jsonStr}`);
this.javaProcess.stdin.write(`${jsonStr}\n`);
const { promise, resolve } = Promise.withResolvers();
this.listeners.set(id, resolve);
return promise;
}
}
上述步骤完成后,就可以在nodejs中通过JSON-RPC 2.0调用Java方法了。
代码4 通过JSON-RPC 2.0调用Java方法
(async () => {
const client = new JsonRpcClient();
try {
let response = await client.call('hello', { name: 'Bob' })
console.log(`接收 ${response}`);
response = await client.call('non_exist');
console.log(`接收 ${response}`);
response = await client.call('exit');
console.log(`接收 ${response}`);
} catch (err) {
console.error('RPC call failed:', err);
}
})();
2. 适用场景、局限和扩展
用于对性能要求不高的nodejs程序(如cli),快速对接现有Java库中的方法。如果对性能要求较高,或调用的Java方法需要支持复杂对象,可以使用node-java实现nodejs和Java的互操作。
由于使用了标准输入输出,上述方案对请求和应答对象的数据类型和大小存在一定限制。如果需要传输少量二进制数据,可以使用十六进制编码或base64编码。如果要传输大量数据,可以首先生成临时文件,将临时文件名作为参数传递。上述方案也可以扩展到“发布-订阅”模式。
3. 示例代码
代码5 Javalib.java
public class Javalib {
public String hello(String name) {
return "Hello " + name + " from Java!";
}
}
代码6 JsonRpcServer.java
// 需要下载org.json包。https://repo1.maven.org/maven2/org/json/json/20250517/json-20250517.jar
import java.io.*;
import java.util.Scanner;
import java.util.Objects;
import org.json.JSONObject;
import org.json.JSONArray;
public class JsonRpcServer {
public boolean running = true;
private JSONObject serve(JSONObject request) {
String method = request.getString("method");
int id = request.getInt("id");
JSONObject params = request.getJSONObject("params");
JSONObject response = new JSONObject();
response.put("jsonrpc", "2.0");
response.put("id", id);
JSONObject error = new JSONObject();
switch (String.valueOf(method)) {
case "hello": {
String name = params.getString("name");
Javalib javalib = new Javalib();
String result = javalib.hello(name);
response.put("result", result);
break;
}
case "exit":
response.put("result", "exit");
running = false;
break;
default:
error.put("code", -32601);
error.put("messsage", "method not found");
response.put("error", error);
break;
}
return response;
}
private String serve(String jsonStr) {
JSONObject request = new JSONObject(jsonStr);
JSONObject response = serve(request);
return response.toString();
}
public static void main(String[] args) throws IOException {
JsonRpcServer server = new JsonRpcServer();
Scanner scanner = new Scanner(System.in);
while (server.running) {
String jsonStr = scanner.nextLine();
System.out.println(server.serve(jsonStr));
}
}
}
代码7 app.js
import { spawn } from 'child_process';
class JsonRpcClient {
constructor() {
this.counter = 0;
this.listeners = new Map();
this.javaProcess = spawn('java', ['-cp', 'Javalib.jar;json-20250517.jar;.', 'JsonRpcServer']);
this.javaProcess.stdout.on('data', (data) => {
const jsonStr = data.toString();
try {
const { id, result } = JSON.parse(jsonStr);
if (this.listeners.has(id)) {
this.listeners.get(id)(jsonStr);
this.listeners.delete(id);
}
} catch (err) {
console.error('Failed to parse response:', err);
}
});
this.javaProcess.stderr.on('data', (data) => {
console.error('Java process error:', data.toString());
});
}
async call(method, params = {}) {
const id = ++this.counter;
const request = {
jsonrpc: "2.0",
id,
method,
params,
};
const jsonStr = JSON.stringify(request);
console.log(`发送 ${jsonStr}`);
this.javaProcess.stdin.write(`${jsonStr}\n`);
const { promise, resolve } = Promise.withResolvers();
this.listeners.set(id, resolve);
return promise;
}
}
(async () => {
const client = new JsonRpcClient();
try {
let response = await client.call('hello', { name: 'Bob' })
console.log(`接收 ${response}`);
response = await client.call('non_exist');
console.log(`接收 ${response}`);
response = await client.call('exit');
console.log(`接收 ${response}`);
} catch (err) {
console.error('RPC call failed:', err);
}
})();
代码8 测试输入input.text
{"jsonrpc": "2.0", "id": 1, "method": "hello", "params": {"name": "Alex"}}
{"jsonrpc": "2.0", "id": 1, "method": "exit", "params": {}}
代码9 测试脚本
# 编译Javalib javac Javalib.java && jar cvf Javalib.jar Javalib.class # 编译JsonRpcServer javac -cp "Javalib.jar;json-20250517.jar" JsonRpcServer.java # 测试JsonRpcServer gc input.txt | java -cp "Javalib.jar;json-20250517.jar;." JsonRpcServer # 测试app.js node app.js
4. 附录:JSON-RPC 2.0简介
JSON-RPC 2.0是一种轻量级、无状态的远程过程调用(RPC)协议,使用JSON作为数据交换格式。
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| jsonrpc | string | 是 | 固定为 "2.0" |
| method | string | 是 | 方法名 |
| params | array/object | 否 | 参数 |
| id | string/number | 否 | 请求标识符 |
代码10 请求对象示例
{
"jsonrpc": "2.0",
"method": "subtract",
"params": [42, 23],
"id": 1
}
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| jsonrpc | string | 是 | 固定为 "2.0" |
| result | any | 否 | 结果 |
| error | 错误对象 | 否 | 错误信息 |
| id | string/number | 是 | 与请求标识符一致 |
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | number | 是 | 错误码 |
| message | string | 是 | 错误简介 |
| data | any | 否 | 详细信息 |
| 错误码 | 说明 | |
|---|---|---|
| -32700 | Parse error | 语法解析错误 |
| -32600 | Invalid Request | 无效请求 |
| -32601 | Method not found | 找不到方法 |
| -32602 | Invalid params | 无效的参数 |
| -32603 | Internal error | 内部错误 |
| -32000 到 -32099 | Server error | 服务端错误 |
| 语言 | 库/框架 |
|---|---|
| JavaScript | json-rpc-protocol |
| Python | jsonrpcserver |
| Go | jsonrpc2 |
| Java | jsonrpc4j |
5. 参考资料
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐




所有评论(0)