首页 java 调用 python
文章
取消

java 调用 python

需求

最近碰到 “需要在 java 中执行 python 代码片段” 的需求。调研了几种方案。

Jython 、Py4j 、jep 、pemja

最后选取了 Py4j 方案。

实现方案

java端开发

在 springboot 启动时,创建 GatewayServer,然后将和 python 交互的类保存下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
@Component
public class Py4jServer implements ApplicationListener<ApplicationStartedEvent> {
  @Override
  public void onApplicationEvent(ApplicationStartedEvent event) {
    try {
      GatewayServer server = new GatewayServer();
      server.start();
      PyEntrypoint pyEntrypoint = (PyEntrypoint) server.getPythonServerEntryPoint(new Class[]{PyEntrypoint.class});
      FlowHelper.pyEntrypoint = pyEntrypoint;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
  }
}
1
2
3
4
5
6
public interface PyEntrypoint {

    String execute(String code, String globalParams, String localParams, String globalParamsDefine);

    String shutdown();
}

python开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import json
import threading
import time

from py4j.java_gateway import JavaGateway, GatewayParameters, CallbackServerParameters


class PyEntrypoint(object):
    gateway_ref:JavaGateway = None
    class Java:
        implements = ["com.demo.PyEntrypoint"]

    def execute(self, code, global_params, local_params, global_params_define):
        try:
            print("接受请求:" + global_params)
            gp = json.loads(global_params)
            lp = json.loads(local_params)
            gpd = json.loads(global_params_define)
            exec(code, gp, lp)
            del[gp['__builtins__']]
            for key in lp.keys():
                if key in gpd:
                    gp[key] = lp[key]
            data = json.dumps(gp)
            print("返回数据:" + data)
            return data
        except Exception as e:
            print(e)

    def shutdown(self):
        try:
            print(time.time())
            # asyncio.create_task(_shutdown())
            thread = threading.Thread(target=self._shutdown_0)
            thread.start()
            print(time.time())
            return "success"
        except Exception as e:
            print(e)

    def _shutdown_0(self):
        try:
            time.sleep(3)
            print(time.time().__str__() + "关闭")
            self.gateway_ref.shutdown()
        except Exception as e:
            print(e)

try:
    pe = PyEntrypoint()
    gateway_param = GatewayParameters()
    gateway = JavaGateway(
        gateway_parameters=gateway_param,
        callback_server_parameters=CallbackServerParameters(),
        python_server_entry_point=pe,
        )
    print("==== 启动 ====")
    print(gateway)
    pe.gateway_ref = gateway
    print("==== 启动 ====")
except Exception as e:
    print(e)

启动python进程

若是服务器无法下载第三方包,只能通过离线安装第三方包 1、创建python虚拟环境

1
2
3
4
python3 -m venv venv
source venv/bin/activate
pip3 install py4j-0.10.9.9-py2.py3-none-any.whl
python3 PyEntrypoint.py

如果需要后台启动,则使用 nohup 命令

nohup python3 -u PyEntrypoint.py > rule.log 2>&1 &

如果需要使用脚本的话

1
2
3
4
5
6
#!/bin/bash

source venv/bin/activate

nohup python3 -u PyEntrypoint.py > rule.log 2>&1 &

本文由作者按照 CC BY 4.0 进行授权