需求
最近碰到 “需要在 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 &