开发者

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)。

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜