Java调用Python服务的三种实现过程
目录
- Java调用python服务过程
- 方法一:通过 REST API 调用(最常用、最推荐)
- 方法二:使用 ProcessBuilder 直接调用Python脚本
- 方法三:使用 Jython(不推荐用于新项目)
- 总结
Java调用Python服务过程
在Java中调用Python服务是一种非常常见的需求,尤其是在利用Python强大的机器学习/数据科学库,或者复用现有Python代码时。
根据不同的应用场景,有几种主流的方法。
方法 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
REST API | 绝大多数生产环境,尤其是微服务架构 | 解耦、伸缩性好、语言无关、生态丰富 | 有网络延迟、需编写接口代码 |
ProcessBuilder | 简单的、调用不频繁的脚本任务,快速原型 | 实现简单、无需额外服务 | 性能开销大、进程管理复杂、交互麻烦 |
Jython | 遗留系统(Python 2.7),且无需第三方C库 | 无进程开销、直接交互 | 仅支持Python 2.7、无法使用主流科算库 |
方法一:通过 REST API 调用(最常用、最推荐)
将Python代码包装成一个HTTP服务器(例如使用Flask或FastAPI),然后Java程序通过HTTP客户端(例如Spring的RestTemplate或OkHttp)像调用其他任何RESTful服务一样来调用它。
①、创建 Python 服务端 (Flask)
首先,确保安装了Flask:pip install flask
创建一个名为 python_server.py 的文件:
from flask import Flask,request,jsonify import math app = Flask(__name__) #定义一个简单的API端点,计算平方根 @app.route('/calculate',methods=['POST']) def calculate(): data = request.get_json() number = data['number'] result = math.sqrt(number) return jsonify({'result': result, 'python_version': '计算完成'}) #文本处理 @app.route('/process_text', methods=['POST']) def process_text(): data = request.get_json() text = data['text'] processed_text = text.upper() + " - Processed by Python" return jsonify({'processed_text': processed_text}) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)
运行这个Python脚本:python python_server.py。现在Python服务就在本地的5000端口运行了。
②、创建java客户端
使用Spring Boot的RestTemplate(传统方式)和新的WebClient(响应式)作为示例。
使用 RestTemplate (Spring Boot 2.x)
首先,pom.XML中确保有Spring Web依赖。
public class PythonServiceClient { public static void main(String[] args) { RestTemplate restTemplate = new RestTemplate(); String pythonServiceUrl = "http://localhost:5000/calculate"; // 准备请求数据 Map<String, Object> requestMap = new HashMap<>(); requestMap.put("number", 9.0); // 发送POST请求并获取响应 ResponseEntity<Map> response = restTemplate.postForEnt编程客栈ity( pythonServiceUrl, requestMap, Map.class ); // 处理响应 if (response.getStatusCode().is2xxSuccessful()) { Map<String, Object> responseBody = response.getBody(); System.out.println("计算结果: " + responseBody.get("result")); System.out.println("信息: " + responseBody.get("python_version")); } else { System.out.println("请求失败: " + response.getStatusCode()); } } }
使用 WebClient (Spring 5+ 响应式)
首先,在pom.xml中添加Spring WebFlux依赖。
public class PythonServiceWebClient { public static void main(String[] args) throws InterruptedException { WebClient webClient = WebClient.create("http://localhost:5000"); Mono<Map> responseMono = webCliwww.devze.coment.post() .uri("/process_text") .bodyValue(Collections.singletonMap("text", "hello from java")) www.devze.com .retrieve() .bodyToMono(Map.class); // 异步非阻塞地获取结果 responseMono.subscribe(response -> { System.out.println("处理后的文本: " + response.get("processed_text")); }); // 等待异步操作完成(实际生产环境中不需要这样) Thread.sleep(1000); } }
方法二:使用 ProcessBuilder 直接调用Python脚本
这种方法直接在Java中启动一个操作系统进程来运行Python解释器并执行指定的脚本。Java通过进程的输入输出流与Python脚本交换数据。
①、创建 Python 脚本 (math_utils.py)
# 这是一个简单的Python脚本,从标准输入读取JSON,计算后输出JSON import sys import json import math def main(): # 从标准输入读取数据 data = sys.stdin.read() try: request_data = json.loads(data) number = request_data['number'] # 执行计算 result = math.sqrt(number) # 输出结果到标准输出 print(json.dumps({ "result": result, "status": "success" })) except Exception as e: print(json.dumps({ "status": "error", "message": str(e) })) if __name__ == "__main__": main()
②、Java 代码调用该脚本
public class ProcessBuilderExample { public static void main(String[] args) throws IOException, InterruptedException { // 1. 定义Python解释器和脚本路径 String pythonInterpreter = "python3"; // 或 "python",取决于系统 String pythonScriptPath = "/path/to/your/math_utils.py"; // 替换为你的脚本绝对路径 // 2. 构建命令 ProcessBuilder processBuilder = new ProcessBuilder( pythonInterpreter, "-u", // 强制标准输出和错误无缓冲,很重要! pythonScriptPath ); processBuilder.redirectErrorStream(true); // 将错误流合并到输入流 // 3. 启动进程 Process process = processBuilder.st编程客栈art(); // 4. 准备输入数据并通过输出流发送给Python脚本 Map<String, Object> inputData = new HashMap<>(); inputData.put("number", 16.javascript0); String jsonInput = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(inputData); // 可以使用任何JSON库 try (Bufferedwriter writer = new BufferedWriter( new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) { writer.write(jsonInput); writer.flush(); } // 5. 读取Python脚本的输出 StringBuilder output = new StringBuilder(); try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; while ((line = reader.readLine()) != null) { output.append(line); } } // 6. 等待进程结束并获取返回值 int exitCode = process.waitFor(); if (exitCode == 0) { // 解析Python脚本的输出 Map<String, Object> result = new com.fasterxml.jackson.databind.ObjectMapper().readValue( output.toString(), Map.class); System.out.println("成功: " + result.get("result")); } else { System.err.println("Python脚本执行错误: "); System.err.println(output); } } }
方法三:使用 Jython(不推荐用于新项目)
Jython是一个JVM实现,可以直接在JVM上运行Python代码,并允许Java和Python对象直接交互。
只支持Python 2.7,无法使用基于C的Python库(如NumPy, Pandas, TensorFlow, PyTorch等),项目活跃度低。
①、将Jython的jar包(如jython-standalone-2.7.3.jar)添加到项目的classpath中。
②、Java代码
public class JythonExample { public static void main(String[] args) { try (PythonInterpreter pyInterp = new PythonInterpreter()) { // 执行简单的Python语句 pyInterp.exec("print('Hello from Jython!)"); pyInterp.exec("import math"); // 在Python中设置变量,在Java中获取 pyInterp.set("a", 10); pyInterp.exec("b = math.sqrt(a)"); Number b = (Number) pyInterp.get("b"); System.out.println("Square root of 10 from Jython: " + b); } } }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论