当前位置: 代码网 > it编程>编程语言>Java > Java调用Python服务的三种实现过程

Java调用Python服务的三种实现过程

2025年10月13日 Java 我要评论
java调用python服务过程在java中调用python服务是一种非常常见的需求,尤其是在利用python强大的机器学习/数据科学库,或者复用现有python代码时。根据不同的应用场景,有几种主流

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.postforentity(
                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 = webclient.post()
                .uri("/process_text")
                .bodyvalue(collections.singletonmap("text", "hello from java"))
                .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.start();

        // 4. 准备输入数据并通过输出流发送给python脚本
        map<string, object> inputdata = new hashmap<>();
        inputdata.put("number", 16.0);
        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);
        }
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com