java - 使用 Jython 在 Spring Boot 应用程序中包含 Python 脚本失败 - 找不到模块

标签 java python spring jython

我正在尝试习惯 python+java 交互,所以我写了一个小 python 脚本,我想从我的 Spring Boot Application 执行该脚本。 。该脚本位于(相对于 .java -文件)路径 /scripts_py/getStockPrice.py 中。包含 getStockPrice -方法(参见下面的代码)。所以我集成了jython并尝试执行以下CronJob :

@Component
public class CronService {

    private PythonScriptSingleton pss = PythonScriptSingleton.getInstance();
    private final Logger logger = LoggerFactory.getLogger(CronService.class);

    //call every 5 sec
    @Scheduled(fixedRate = 5000)
    public void initStockPriceAPICall() {
        this.getStockPrice("NFLX");
    }

    public void getStockPrice(String ticker) {
        String result = (String) (Object) this.pss.getFunc_getPriceForTicker().__call__(new PyString(ticker));
        try {
            logger.info("Price is " + result);
        } catch (NullPointerException e) {
            logger.info("Catched NPE");
        }

    }
}

PythongScriptSingleton (我的想法是,我可能需要多次执行该脚本 - 所以我尝试使用此类的 singleton 实例来保存该脚本,这样我就不需要每次都重新编译它:

public class PythonScriptSingleton {

    private static PythonScriptSingleton ps;

    public static PythonScriptSingleton getInstance() {
        if (ps == null) {
            ps = new PythonScriptSingleton();
            ps.initScript();
        }
        return ps;
    }

    private PyObject func_getPriceForTicker;

    private PythonScriptSingleton() {

    }

    private void initScript() {
        PythonInterpreter interpreter = new PythonInterpreter();
        String fileUrlPath = "/scripts_py";
        String scriptName = "getStockPrice.py";
        interpreter.exec("import sys\n" + "import os \n" + "sys.path.append('" + fileUrlPath + "')\n" + "from "
                + scriptName + " import * \n");
        String funcName = "getStockPrice";
        PyObject someFunc = interpreter.get(funcName);
        this.func_getPriceForTicker = someFunc;
        interpreter.close();
    }

    public PyObject getFunc_getPriceForTicker() {
        return func_getPriceForTicker;
    }
}

Python 脚本:

from yahoo_fin import stock_info as si

def getStockPrice(ticker):
    price = si.get_live_price(ticker)
    return price

我正在使用嵌入式tomcatSpring Boot (可执行文件 JAR -文件)和 jython-standalone 2.7.2 :

   <dependency>
        <groupId>org.python</groupId>
        <artifactId>jython-standalone</artifactId>
        <version>2.7.2</version>
    </dependency>

我不断遇到的错误说,脚本未定义 - 我尝试使用和不使用文件结尾( .py )来定义它,两者都没有改变任何内容:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.fr.stockticker.pythoninteraction.CronService]: Constructor threw exception; nested exception is Traceback (most recent call last):
  File "<string>", line 4, in <module>
ImportError: No module named getStockPrice

        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:217) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
        ... 81 common frames omitted
Caused by: org.python.core.PyException: ImportError: No module named getStockPrice
        at org.python.core.Py.ImportError(Py.java:329) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.imp.import_first(imp.java:1230) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.imp.import_module_level(imp.java:1361) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.imp.importName(imp.java:1528) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.ImportFunction.__call__(__builtin__.java:1285) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.PyObject.__call__(PyObject.java:433) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.__builtin__.__import__(__builtin__.java:1232) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.imp.importAll(imp.java:1647) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.pycode._pyx0.f$0(<string>:4) ~[na:na]
        at org.python.pycode._pyx0.call_function(<string>) ~[na:na]
        at org.python.core.PyTableCode.call(PyTableCode.java:173) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.PyCode.call(PyCode.java:18) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.Py.runCode(Py.java:1687) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.core.Py.exec(Py.java:1731) ~[jython-standalone-2.7.2.jar:2.7.2]
        at org.python.util.PythonInterpreter.exec(PythonInterpreter.java:268) ~[jython-standalone-2.7.2.jar:2.7.2]
        at de.fr.stockticker.pythoninteraction.PythonScriptSingleton.initScript(PythonScriptSingleton.java:28) ~[classes/:na]
        at de.fr.stockticker.pythoninteraction.PythonScriptSingleton.getInstance(PythonScriptSingleton.java:13) ~[classes/:na]
        at de.fr.stockticker.pythoninteraction.CronService.<init>(CronService.java:12) ~[classes/:na]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_251]
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_251]
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_251]
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_251]
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:204) ~[spring-beans-5.2.5.RELEASE.jar:5.2.5.RELEASE]
        ... 83 common frames omitted

最佳答案

我能够部分使用 Jython 运行您的程序 - 我无法从 yahoo 获取库存流程,该流程内部依赖于 numpy,并且看起来 Jython 不支持 numpy,因为它是 cpython 库。

private void initScript() { 
    PythonInterpreter interpreter = new PythonInterpreter(); 
    String fileUrlPath = "/users/sagar/demo/src/main/resources/python"; 
    interpreter.exec("import sys"); 
    interpreter.exec("sys.path.append('" + fileUrlPath + "')"); 
    interpreter.exec("from getStockPrice import *"); this.func_getPriceForTicker = 
    interpreter.get("getStockPrice", PyFunction.class); 
    interpreter.close(); 
}

您将能够克服错误,但您会看到错误

Missing required dependencies ['numpy'] 

所以我尝试使用另一个java python库 jep并进行了如下更改

@SpringBootApplication
@EnableScheduling
public class DemoApplication  {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    private final Logger logger = LoggerFactory.getLogger(DemoApplication.class);

    //call every 5 sec
    @Scheduled(fixedRate = 5000)
    public void initStockPriceAPICall() throws JepException {
        this.getStockPrice("NFLX");
    }

    private void getStockPrice(String ticker) throws JepException {
        try (Interpreter interp = new SharedInterpreter()) {
            String fileUrlPath = "/users/sagar/demo/src/main/resources/python";
            interp.exec("import sys");
            interp.exec("sys.path.append('" + fileUrlPath + "')");
            interp.exec("from getStockPrice import *");
            interp.set("ticker", ticker);
            interp.exec("price = getStockPrice(ticker)");
            Object result = interp.getValue("price");
            logger.info("Price is " + result);
        }
    }
}

pom.xml

<dependency>
    <groupId>black.ninia</groupId>
    <artifactId>jep</artifactId>
    <version>3.9.0</version>
</dependency>

确保安装 jep 模块 - 它具有 native 库

pip install jeb

添加java库路径以加载原生库

-Djava.library.path=/usr/local/lib/python2.7/site-packages/jep

引用 - https://github.com/ninia/jep/wiki/Getting-Started

enter image description here

关于java - 使用 Jython 在 Spring Boot 应用程序中包含 Python 脚本失败 - 找不到模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61442602/

相关文章:

Python运行时错误: maximum recursion depth exceeded in cmp

python - 循环遍历嵌套生成器一次并重复

java - AsyncContext 响应与原始传入请求不匹配?

java - 如何配置事务管理以在 Spring 中使用 2 个不同的数据库?

Java方法重写/接口(interface)问题

Java编译错误: Cannot Find Symbol for BufferedReader

java - java中双向链表实现的效率

java - Java 的 GWT 网格替代方案

python - 如何从python中的多个词典中获取一个键的值?

java - Spring Hibernate Template 执行方法为 Oracle 上的计数查询返回什么对象类型?